From 62f36fb5e57eacc7c2d9ae989221b6ec615e6f97 Mon Sep 17 00:00:00 2001 From: alex-s168 Date: Sat, 22 Feb 2025 07:44:59 +0100 Subject: [PATCH 1/3] unversal serialization --- PLATFORM/C/LIB/serial.lsts | 286 +++++++++++++++++++++++++++++++++++++ 1 file changed, 286 insertions(+) create mode 100644 PLATFORM/C/LIB/serial.lsts diff --git a/PLATFORM/C/LIB/serial.lsts b/PLATFORM/C/LIB/serial.lsts new file mode 100644 index 000000000..6e5021fe2 --- /dev/null +++ b/PLATFORM/C/LIB/serial.lsts @@ -0,0 +1,286 @@ + +type SerialVal = SerialUInt { val: U64 } + | SerialInt { val: I64 } + | SerialFlt { val: F64 } + | SerialBool { val: U8 } + | SerialStr { val: String } + | SerialVec { val: Vector } + | SerialDict { val: HashtableEq } + ; + +interface Serializable { + let serialize(self: Serializable): SerialVal; +} + +interface Deserializable { + let deserialize(val: SerialVal, ty: Type): Deserializable; +} + +# TODO: failable casts between number types + +type SerialVal => Serializable; +type SerialVal => Deserializable; + +let deserialize(val: SerialVal, ty: Type): SerialVal = ( + val +); + +let serialize(val: SerialVal): SerialVal = ( + val +); + +type Bool => Serializable; +type Bool => Deserializable; + +let deserialize(vali: SerialVal, ty: Type): Bool = ( + deserialize(vali,type(U64)) as Bool +); + +let serialize(val: Bool): SerialVal = ( + SerialBool { val } +); + +type U64 => Serializable; +type U64 => Deserializable; + +let deserialize(vali: SerialVal, ty: Type): U64 = ( + match vali { + SerialBool { val=val } => ( val as U64 ); + SerialUInt { val=val } => ( val ); + SerialInt { val=val } => ( + if val < 0 { + fail("cannot deserialize negative int to u64"); + }; + val as U64 + ); + SerialFlt { val=val } => ( + if val != ((val as U64) as F64) { + fail("cannot deserialize decimal number to u64"); + }; + if val < 0 { + fail("cannot deserialize negative number to u64"); + }; + val as U64 + ); + SerialStr { val=val } => ( to-u64(val) ); + other => ( fail("cannot deserialize u64 from this SerialVal"); ); + } +); + +let serialize(val: U64): SerialVal = ( + SerialUInt { val } +); + +type I64 => Serializable; +type I64 => Deserializable; + +let deserialize(vali: SerialVal, ty: Type): I64 = ( + match vali { + SerialBool { val=val } => ( val as I64 ); + SerialUInt { val=val } => ( val as I64 ); + SerialInt { val=val } => ( val ); + SerialFlt { val=val } => ( + if val != ((val as I64) as F64) { + fail("cannot deserialize decimal number to i64"); + }; + val as I64 + ); + SerialStr { val=val } => ( to-i64(val) ); + other => ( fail("cannot deserialize i64 from this SerialVal"); ); + } +); + +let serialize(val: I64): SerialVal = ( + SerialInt { val } +); + +type F64 => Serializable; +type F64 => Deserializable; + +let deserialize(vali: SerialVal, ty: Type): F64 = ( + match vali { + SerialBool { val=val } => ( val as F64 ); + SerialUInt { val=val } => ( val as F64 ); + SerialInt { val=val } => ( val as F64 ); + SerialFlt { val=val } => ( val ); + SerialStr { val=val } => ( to-f64(val) ); + other => ( fail("cannot deserialize f64 from this SerialVal"); ); + } +); + +let serialize(val: F64): SerialVal = ( + SerialFlt { val } +); + +type String => Serializable; +type String => Deserializable; + +let deserialize(vali: SerialVal, ty: Type): String = ( + match vali { + SerialStr { val=val } => ( val ); + other => ( fail("cannot deserialize string from this SerialVal"); ); + } +); + +let serialize(val: String): SerialVal = ( + SerialStr { val } +); + +type CString => Serializable; +type CString => Deserializable; + +let deserialize(vali: SerialVal, ty: Type): CString = ( + match vali { + SerialStr { val=val } => ( untern(val) ); + other => ( fail("cannot deserialize string from this SerialVal"); ); + } +); + +let serialize(val: CString): SerialVal = ( + SerialStr { (to-smart-string(val)) } +); + +type Iterable => Serializable; +type FromVector => Deserializable; + +let deserialize(vali: SerialVal, ty: Type>): ot = ( + match vali { + SerialVec { val=val } => ( + let out = mk-vector(type(eltt), val.length()); + for x in val.unsafe-iter() { + out = out.push(deserialize(x,type(eltt))); + }; + out.move-to(ty) + ); + r => ( fail("can only deserialize collection from serialvec"); ); + } +); + +let serialize(self: Iterable): SerialVal = ( + let out = mk-vector(type(SerialVal), length-or-zero(self)); + for x in self.unsafe-iter() { + out = out.push(close(serialize(x))); + }; + SerialVec { out } +); + +type HashtableEq => Serializable; +type HashtableEq => Deserializable; + +let deserialize(val: SerialVal, ty: Type>): HashtableEq = ( + let out = {} :: HashtableEq; + match val { + SerialDict { val=val } => ( + for kv in val.unsafe-iter() { + let k = deserialize(open(kv.first), type(k)); + let v = deserialize(open(kv.second), type(v)); + out = out.bind(k, v); + }; + ); + r => ( fail("can only deserialize map from serialdict") ); + }; + out +); + +let serialize(self: HashtableEq): SerialVal = ( + let out = {} :: HashtableEq; + + for x in self.unsafe-iter() { + out = out.bind( + close(serialize(x.first)), + close(serialize(x.second))); + }; + + SerialDict { out } +); + +type JsonSerializeCfg = JsonSerializeCfg { pretty: U8, indent: U64 }; + +let to-smart-string(self: SerialVal): String = ( + self.to-json(JsonSerializeCfg { true, 2 }, 0) +); + +let to-smart-string(self: Serializable): String = ( + to-smart-string(serialize(self)) +); + +let .to-json(self: SerialVal, cfg: JsonSerializeCfg, depth: U64): String = ( + match self { + SerialUInt { val=val } => ( to-smart-string(val) ); + SerialInt { val=val } => ( to-smart-string(val) ); + SerialFlt { val=val } => ( to-smart-string(val) ); + + SerialBool { val=val } => ( + if val { "true" } + else { "false" } + ); + + SerialStr { val=val } => ( "\"\{val}\"" ); + + SerialVec { val=val } => ( + let out = "["; + if cfg.pretty { + let first = true; + for x in val.unsafe-iter() { + if first { + first = false; + } else { + out = out + ",\n"; + }; + out = out + " ".repeat(depth * cfg.indent); + out = out + open(x).to-json(cfg, depth + 1); + }; + if val.length() > 0 { + out = out + "\n"; + }; + } else { + let first = true; + for x in val.unsafe-iter() { + if first { + first = false; + } else { + out = out + ", "; + }; + out = out + open(x).to-json(cfg, depth + 1); + }; + }; + out = out + "]"; + ); + + SerialDict { val=val } => ( + let out = "{"; + if cfg.pretty { + let first = true; + let any = false; + for x in val.unsafe-iter() { + any = true; + if first { + first = false; + } else { + out = out + ",\n"; + }; + out = out + " ".repeat(depth * cfg.indent); + out = out + open(x.first).to-json(cfg, depth + 1); + out = out + ": "; + out = out + open(x.second).to-json(cfg, depth + 1); + }; + if any { + out = out + "\n"; + }; + } else { + let first = true; + for x in val.unsafe-iter() { + if first { + first = false; + } else { + out = out + ", "; + }; + out = out + open(x.first).to-json(cfg, depth + 1); + out = out + ": "; + out = out + open(x.second).to-json(cfg, depth + 1); + }; + }; + out = out + "}"; + ); + } +); From b740031d2052ee09a3e02500ad94aae897d5a7e7 Mon Sep 17 00:00:00 2001 From: alex-s168 Date: Sat, 22 Feb 2025 07:47:45 +0100 Subject: [PATCH 2/3] add serial.lsts to default.lsts --- PLATFORM/C/LIB/default.lsts | 1 + 1 file changed, 1 insertion(+) diff --git a/PLATFORM/C/LIB/default.lsts b/PLATFORM/C/LIB/default.lsts index 8c432363c..50d10230f 100644 --- a/PLATFORM/C/LIB/default.lsts +++ b/PLATFORM/C/LIB/default.lsts @@ -47,3 +47,4 @@ import PLATFORM/C/LIB/regex.lm; import PLATFORM/C/LIB/cmp.lsts; import PLATFORM/C/LIB/print.lsts; import PLATFORM/C/LIB/umbra.lsts; +import PLATFORM/C/LIB/serial.lsts; From d52f92b93fe05f610811a4797e7f2e495bf24813 Mon Sep 17 00:00:00 2001 From: alex-s168 Date: Thu, 27 Feb 2025 18:10:15 +0100 Subject: [PATCH 3/3] c --- PLATFORM/C/LIB/serial.lsts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/PLATFORM/C/LIB/serial.lsts b/PLATFORM/C/LIB/serial.lsts index 6e5021fe2..3049da1a5 100644 --- a/PLATFORM/C/LIB/serial.lsts +++ b/PLATFORM/C/LIB/serial.lsts @@ -204,6 +204,10 @@ let to-smart-string(self: Serializable): String = ( to-smart-string(serialize(self)) ); +let .to-json(self: SerialVal, cfg: JsonSerializeCfg): String = ( + self.to-json(cfg, 0_u64) +); + let .to-json(self: SerialVal, cfg: JsonSerializeCfg, depth: U64): String = ( match self { SerialUInt { val=val } => ( to-smart-string(val) );