1use std::cell::RefCell;
12use std::rc::Rc;
13
14use logicaffeine_runtime::RtPayload;
15
16pub use logicaffeine_base::describe::{gen_eval, GenCmp, GenExpr};
21use logicaffeine_base::describe::{
22 self, consider, deserialize_gen, detect_affine, emit_best_int_column, serialize_gen,
23 MAX_GEN_DEPTH, MAX_GEN_NODES,
24};
25
26use crate::interpreter::{ClosureValue, InductiveValue, ListRepr, MapStorage, RuntimeValue, StructValue};
27
28#[derive(Debug, Clone, PartialEq, Eq)]
30pub enum MarshalError {
31 NotSendable(&'static str),
34}
35
36pub fn materialize(value: &RuntimeValue) -> Result<RtPayload, MarshalError> {
38 Ok(match value {
39 RuntimeValue::Int(n) => RtPayload::Int(*n),
40 RuntimeValue::BigInt(b) => {
41 let (negative, magnitude) = b.to_le_bytes();
42 RtPayload::BigInt { negative, magnitude }
43 }
44 RuntimeValue::Rational(r) => {
45 let (num_negative, num_magnitude) = r.numerator().to_le_bytes();
46 let (_den_sign, den_magnitude) = r.denominator().to_le_bytes();
47 RtPayload::Rational { num_negative, num_magnitude, den_magnitude }
48 }
49 RuntimeValue::Decimal(d) => {
50 let (negative, magnitude, scale) = d.to_le_bytes();
51 RtPayload::Decimal { negative, magnitude, scale }
52 }
53 RuntimeValue::Money(m) => {
54 let (negative, magnitude, scale) = m.amount.to_le_bytes();
55 RtPayload::Money { negative, magnitude, scale, currency: m.currency.code.to_string() }
56 }
57 RuntimeValue::Uuid(u) => RtPayload::Uuid(u.to_bytes()),
58 RuntimeValue::Complex(c) => {
59 let (re_negative, re_num) = c.re().numerator().to_le_bytes();
60 let (_, re_den) = c.re().denominator().to_le_bytes();
61 let (im_negative, im_num) = c.im().numerator().to_le_bytes();
62 let (_, im_den) = c.im().denominator().to_le_bytes();
63 RtPayload::Complex { re_negative, re_num, re_den, im_negative, im_num, im_den }
64 }
65 RuntimeValue::Modular(m) => {
66 let (_, value) = m.value().to_le_bytes();
67 let (_, modulus) = m.modulus().to_le_bytes();
68 RtPayload::Modular { value, modulus }
69 }
70 RuntimeValue::Float(f) => RtPayload::Float(*f),
71 RuntimeValue::Bool(b) => RtPayload::Bool(*b),
72 RuntimeValue::Char(c) => RtPayload::Char(*c),
73 RuntimeValue::Text(s) => RtPayload::Text((**s).clone()),
74 RuntimeValue::Nothing => RtPayload::Nothing,
75 RuntimeValue::Duration(n) => RtPayload::Duration(*n),
76 RuntimeValue::Date(n) => RtPayload::Date(*n),
77 RuntimeValue::Moment(n) => RtPayload::Moment(*n),
78 RuntimeValue::Span { months, days } => RtPayload::Span { months: *months, days: *days },
79 RuntimeValue::Time(n) => RtPayload::Time(*n),
80 RuntimeValue::Word(w) => RtPayload::Word { width: w.width(), bits: w.to_u64() },
81 RuntimeValue::Lanes(_) => return Err(MarshalError::NotSendable("Lanes8Word32")),
84 RuntimeValue::List(items) => {
85 let vals = items.borrow().to_values();
86 RtPayload::List(vals.iter().map(materialize).collect::<Result<_, _>>()?)
87 }
88 RuntimeValue::Set(items) => {
89 RtPayload::Set(items.borrow().iter().map(materialize).collect::<Result<_, _>>()?)
90 }
91 RuntimeValue::Tuple(items) => {
92 RtPayload::Tuple(items.iter().map(materialize).collect::<Result<_, _>>()?)
93 }
94 RuntimeValue::Map(m) => {
95 let mut pairs = Vec::new();
96 for (k, v) in m.borrow().iter() {
97 pairs.push((materialize(k)?, materialize(v)?));
98 }
99 RtPayload::Map(pairs)
100 }
101 RuntimeValue::Struct(s) => {
102 let mut fields = Vec::new();
103 for (name, v) in s.fields.iter() {
104 fields.push((name.clone(), materialize(v)?));
105 }
106 RtPayload::Struct { type_name: s.type_name.clone(), fields }
107 }
108 RuntimeValue::Inductive(ind) => RtPayload::Inductive {
109 type_name: ind.inductive_type.clone(),
110 constructor: ind.constructor.clone(),
111 args: ind.args.iter().map(materialize).collect::<Result<_, _>>()?,
112 },
113 RuntimeValue::Chan(id) => RtPayload::Chan(*id),
117 RuntimeValue::TaskHandle(id) => RtPayload::TaskHandle(*id),
118 RuntimeValue::Peer(topic) => RtPayload::Peer((**topic).clone()),
120 RuntimeValue::Function(_) => return Err(MarshalError::NotSendable("Function")),
121 RuntimeValue::Crdt(_) => return Err(MarshalError::NotSendable("Crdt")),
124 RuntimeValue::Quantity(qv) => {
127 let (num_negative, num_magnitude) = qv.q.magnitude_si().numerator().to_le_bytes();
128 let (_den_sign, den_magnitude) = qv.q.magnitude_si().denominator().to_le_bytes();
129 let dim = qv.q.dimension();
130 let mut dim_num = Vec::with_capacity(logicaffeine_base::BaseDim::COUNT);
131 let mut dim_den = Vec::with_capacity(logicaffeine_base::BaseDim::COUNT);
132 for d in logicaffeine_base::BaseDim::ALL {
133 let e = dim.exponent(d);
134 dim_num.push(e.numerator());
135 dim_den.push(e.denominator());
136 }
137 RtPayload::Quantity {
138 num_negative,
139 num_magnitude,
140 den_magnitude,
141 dim_num,
142 dim_den,
143 unit_symbol: qv.unit.symbol.to_string(),
144 }
145 }
146 })
147}
148
149pub fn rebuild(payload: RtPayload) -> RuntimeValue {
151 match payload {
152 RtPayload::Nothing => RuntimeValue::Nothing,
153 RtPayload::Int(n) => RuntimeValue::Int(n),
154 RtPayload::BigInt { negative, magnitude } => {
155 RuntimeValue::from_bigint(logicaffeine_base::BigInt::from_le_bytes(negative, &magnitude))
156 }
157 RtPayload::Rational { num_negative, num_magnitude, den_magnitude } => {
158 let num = logicaffeine_base::BigInt::from_le_bytes(num_negative, &num_magnitude);
159 let den = logicaffeine_base::BigInt::from_le_bytes(false, &den_magnitude);
160 match logicaffeine_base::Rational::new(num.clone(), den) {
163 Some(r) => RuntimeValue::from_rational(r),
164 None => RuntimeValue::from_bigint(num),
165 }
166 }
167 RtPayload::Decimal { negative, magnitude, scale } => RuntimeValue::Decimal(Rc::new(
168 logicaffeine_base::Decimal::from_le_bytes(negative, &magnitude, scale),
169 )),
170 RtPayload::Money { negative, magnitude, scale, currency } => {
171 let amount = logicaffeine_base::Decimal::from_le_bytes(negative, &magnitude, scale);
172 let currency = logicaffeine_base::money::currency::by_code(¤cy)
173 .unwrap_or(logicaffeine_base::Currency { code: "XXX", scale: 0 });
174 RuntimeValue::Money(Rc::new(logicaffeine_base::Money { amount, currency }))
175 }
176 RtPayload::Uuid(bytes) => {
177 RuntimeValue::Uuid(Rc::new(logicaffeine_base::Uuid::from_bytes(bytes)))
178 }
179 RtPayload::Complex { re_negative, re_num, re_den, im_negative, im_num, im_den } => {
180 let mk = |neg: bool, num: &[u8], den: &[u8]| {
181 logicaffeine_base::Rational::new(
182 logicaffeine_base::BigInt::from_le_bytes(neg, num),
183 logicaffeine_base::BigInt::from_le_bytes(false, den),
184 )
185 .unwrap_or_else(logicaffeine_base::Rational::zero)
186 };
187 let re = mk(re_negative, &re_num, &re_den);
188 let im = mk(im_negative, &im_num, &im_den);
189 RuntimeValue::Complex(Rc::new(logicaffeine_base::Complex::new(re, im)))
190 }
191 RtPayload::Modular { value, modulus } => {
192 let v = logicaffeine_base::BigInt::from_le_bytes(false, &value);
193 let n = logicaffeine_base::BigInt::from_le_bytes(false, &modulus);
194 match logicaffeine_base::Modular::new(v, n) {
195 Some(m) => RuntimeValue::Modular(Rc::new(m)),
196 None => RuntimeValue::Nothing, }
198 }
199 RtPayload::Quantity { num_negative, num_magnitude, den_magnitude, dim_num, dim_den, unit_symbol } => {
200 let num = logicaffeine_base::BigInt::from_le_bytes(num_negative, &num_magnitude);
201 let den = logicaffeine_base::BigInt::from_le_bytes(false, &den_magnitude);
202 let magnitude = logicaffeine_base::Rational::new(num, den)
203 .unwrap_or_else(logicaffeine_base::Rational::zero);
204 let mut exps = [logicaffeine_base::Exp::ZERO; logicaffeine_base::BaseDim::COUNT];
206 for (i, slot) in exps.iter_mut().enumerate() {
207 let n = dim_num.get(i).copied().unwrap_or(0);
208 let d = dim_den.get(i).copied().unwrap_or(1);
209 *slot = logicaffeine_base::Exp::new(n, if d == 0 { 1 } else { d });
210 }
211 let dim = logicaffeine_base::Dimension::from_exps(exps);
212 let unit = logicaffeine_base::quantity::units::by_name(&unit_symbol)
215 .filter(|u| u.dimension == dim)
216 .unwrap_or_else(|| {
217 logicaffeine_base::Unit::linear("", dim, logicaffeine_base::Rational::one())
218 });
219 let q = logicaffeine_base::Quantity::si(magnitude, dim);
220 RuntimeValue::Quantity(Rc::new(crate::interpreter::QuantityValue { q, unit }))
221 }
222 RtPayload::Float(f) => RuntimeValue::Float(f),
223 RtPayload::Bool(b) => RuntimeValue::Bool(b),
224 RtPayload::Char(c) => RuntimeValue::Char(c),
225 RtPayload::Text(s) => RuntimeValue::Text(Rc::new(s)),
226 RtPayload::Duration(n) => RuntimeValue::Duration(n),
227 RtPayload::Date(n) => RuntimeValue::Date(n),
228 RtPayload::Moment(n) => RuntimeValue::Moment(n),
229 RtPayload::Span { months, days } => RuntimeValue::Span { months, days },
230 RtPayload::Time(n) => RuntimeValue::Time(n),
231 RtPayload::Word { width, bits } => match logicaffeine_base::WordVal::from_u64(width, bits) {
232 Some(w) => RuntimeValue::Word(w),
233 None => RuntimeValue::Int(bits as i64),
235 },
236 RtPayload::List(items) => {
237 let vals: Vec<RuntimeValue> = items.into_iter().map(rebuild).collect();
238 RuntimeValue::List(Rc::new(RefCell::new(ListRepr::from_values(vals))))
239 }
240 RtPayload::Set(items) => {
241 RuntimeValue::Set(Rc::new(RefCell::new(items.into_iter().map(rebuild).collect())))
242 }
243 RtPayload::Tuple(items) => {
244 RuntimeValue::Tuple(Rc::new(items.into_iter().map(rebuild).collect()))
245 }
246 RtPayload::Map(pairs) => {
247 let m: MapStorage = pairs.into_iter().map(|(k, v)| (rebuild(k), rebuild(v))).collect();
248 RuntimeValue::Map(Rc::new(RefCell::new(m)))
249 }
250 RtPayload::Struct { type_name, fields } => {
251 let f = fields.into_iter().map(|(k, v)| (k, rebuild(v))).collect();
252 RuntimeValue::Struct(Box::new(StructValue { type_name, fields: f }))
253 }
254 RtPayload::Inductive { type_name, constructor, args } => {
255 RuntimeValue::Inductive(Box::new(InductiveValue {
256 inductive_type: type_name,
257 constructor,
258 args: args.into_iter().map(rebuild).collect(),
259 }))
260 }
261 RtPayload::Chan(id) => RuntimeValue::Chan(id),
262 RtPayload::TaskHandle(id) => RuntimeValue::TaskHandle(id),
263 RtPayload::Peer(topic) => RuntimeValue::Peer(Rc::new(topic)),
264 }
265}
266
267#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)]
288enum WireValue {
289 Nothing,
290 Int(i64),
291 BigInt { negative: bool, magnitude: Vec<u8> },
292 Rational { num_negative: bool, num_magnitude: Vec<u8>, den_magnitude: Vec<u8> },
293 Decimal { negative: bool, magnitude: Vec<u8>, scale: u32 },
294 Money { negative: bool, magnitude: Vec<u8>, scale: u32, currency: std::string::String },
295 Uuid([u8; 16]),
296 Complex {
297 re_negative: bool,
298 re_num: Vec<u8>,
299 re_den: Vec<u8>,
300 im_negative: bool,
301 im_num: Vec<u8>,
302 im_den: Vec<u8>,
303 },
304 Modular { value: Vec<u8>, modulus: Vec<u8> },
305 Quantity {
306 num_negative: bool,
307 num_magnitude: Vec<u8>,
308 den_magnitude: Vec<u8>,
309 dim_num: Vec<i32>,
310 dim_den: Vec<i32>,
311 unit_symbol: String,
312 },
313 Float(f64),
314 Bool(bool),
315 Char(char),
316 Text(String),
317 Duration(i64),
318 Date(i32),
319 Moment(i64),
320 Span { months: i32, days: i32 },
321 Time(i64),
322 Word { width: u32, bits: u64 },
323 Peer(String),
324 List(Vec<WireValue>),
325 Tuple(Vec<WireValue>),
326 Set(Vec<WireValue>),
327 Map(Vec<(WireValue, WireValue)>),
328 Struct { type_name: String, fields: Vec<(String, WireValue)> },
329 Inductive { type_name: String, constructor: String, args: Vec<WireValue> },
330}
331
332#[derive(serde::Serialize, serde::Deserialize)]
334struct WireMessage {
335 from: String,
336 msg: WireValue,
337}
338
339fn rt_to_wire(p: &RtPayload) -> Option<WireValue> {
342 Some(match p {
343 RtPayload::Nothing => WireValue::Nothing,
344 RtPayload::Int(n) => WireValue::Int(*n),
345 RtPayload::BigInt { negative, magnitude } => {
346 WireValue::BigInt { negative: *negative, magnitude: magnitude.clone() }
347 }
348 RtPayload::Rational { num_negative, num_magnitude, den_magnitude } => WireValue::Rational {
349 num_negative: *num_negative,
350 num_magnitude: num_magnitude.clone(),
351 den_magnitude: den_magnitude.clone(),
352 },
353 RtPayload::Decimal { negative, magnitude, scale } => {
354 WireValue::Decimal { negative: *negative, magnitude: magnitude.clone(), scale: *scale }
355 }
356 RtPayload::Money { negative, magnitude, scale, currency } => WireValue::Money {
357 negative: *negative,
358 magnitude: magnitude.clone(),
359 scale: *scale,
360 currency: currency.clone(),
361 },
362 RtPayload::Uuid(bytes) => WireValue::Uuid(*bytes),
363 RtPayload::Complex { re_negative, re_num, re_den, im_negative, im_num, im_den } => {
364 WireValue::Complex {
365 re_negative: *re_negative,
366 re_num: re_num.clone(),
367 re_den: re_den.clone(),
368 im_negative: *im_negative,
369 im_num: im_num.clone(),
370 im_den: im_den.clone(),
371 }
372 }
373 RtPayload::Modular { value, modulus } => {
374 WireValue::Modular { value: value.clone(), modulus: modulus.clone() }
375 }
376 RtPayload::Quantity { num_negative, num_magnitude, den_magnitude, dim_num, dim_den, unit_symbol } => {
377 WireValue::Quantity {
378 num_negative: *num_negative,
379 num_magnitude: num_magnitude.clone(),
380 den_magnitude: den_magnitude.clone(),
381 dim_num: dim_num.clone(),
382 dim_den: dim_den.clone(),
383 unit_symbol: unit_symbol.clone(),
384 }
385 }
386 RtPayload::Float(f) => WireValue::Float(*f),
387 RtPayload::Bool(b) => WireValue::Bool(*b),
388 RtPayload::Char(c) => WireValue::Char(*c),
389 RtPayload::Text(s) => WireValue::Text(s.clone()),
390 RtPayload::Duration(n) => WireValue::Duration(*n),
391 RtPayload::Date(n) => WireValue::Date(*n),
392 RtPayload::Moment(n) => WireValue::Moment(*n),
393 RtPayload::Span { months, days } => WireValue::Span { months: *months, days: *days },
394 RtPayload::Time(n) => WireValue::Time(*n),
395 RtPayload::Word { width, bits } => WireValue::Word { width: *width, bits: *bits },
396 RtPayload::Peer(topic) => WireValue::Peer(topic.clone()),
397 RtPayload::List(items) => WireValue::List(rt_seq_to_wire(items)?),
398 RtPayload::Tuple(items) => WireValue::Tuple(rt_seq_to_wire(items)?),
399 RtPayload::Set(items) => WireValue::Set(rt_seq_to_wire(items)?),
400 RtPayload::Map(pairs) => {
401 let mut wire_pairs = pairs
402 .iter()
403 .map(|(k, v)| Some((rt_to_wire(k)?, rt_to_wire(v)?)))
404 .collect::<Option<Vec<_>>>()?;
405 wire_pairs.sort_by(|a, b| canon_bytes(&a.0).cmp(&canon_bytes(&b.0)));
408 WireValue::Map(wire_pairs)
409 }
410 RtPayload::Struct { type_name, fields } => {
411 let mut wire_fields = fields
412 .iter()
413 .map(|(n, v)| Some((n.clone(), rt_to_wire(v)?)))
414 .collect::<Option<Vec<_>>>()?;
415 wire_fields.sort_by(|a, b| a.0.cmp(&b.0));
417 WireValue::Struct { type_name: type_name.clone(), fields: wire_fields }
418 }
419 RtPayload::Inductive { type_name, constructor, args } => WireValue::Inductive {
420 type_name: type_name.clone(),
421 constructor: constructor.clone(),
422 args: rt_seq_to_wire(args)?,
423 },
424 RtPayload::Chan(_) | RtPayload::TaskHandle(_) => return None,
426 })
427}
428
429fn rt_seq_to_wire(items: &[RtPayload]) -> Option<Vec<WireValue>> {
430 items.iter().map(rt_to_wire).collect()
431}
432
433fn wire_to_rt(w: WireValue) -> RtPayload {
435 match w {
436 WireValue::Nothing => RtPayload::Nothing,
437 WireValue::Int(n) => RtPayload::Int(n),
438 WireValue::BigInt { negative, magnitude } => RtPayload::BigInt { negative, magnitude },
439 WireValue::Rational { num_negative, num_magnitude, den_magnitude } => {
440 RtPayload::Rational { num_negative, num_magnitude, den_magnitude }
441 }
442 WireValue::Decimal { negative, magnitude, scale } => {
443 RtPayload::Decimal { negative, magnitude, scale }
444 }
445 WireValue::Money { negative, magnitude, scale, currency } => {
446 RtPayload::Money { negative, magnitude, scale, currency }
447 }
448 WireValue::Uuid(bytes) => RtPayload::Uuid(bytes),
449 WireValue::Complex { re_negative, re_num, re_den, im_negative, im_num, im_den } => {
450 RtPayload::Complex { re_negative, re_num, re_den, im_negative, im_num, im_den }
451 }
452 WireValue::Modular { value, modulus } => RtPayload::Modular { value, modulus },
453 WireValue::Quantity { num_negative, num_magnitude, den_magnitude, dim_num, dim_den, unit_symbol } => {
454 RtPayload::Quantity { num_negative, num_magnitude, den_magnitude, dim_num, dim_den, unit_symbol }
455 }
456 WireValue::Float(f) => RtPayload::Float(f),
457 WireValue::Bool(b) => RtPayload::Bool(b),
458 WireValue::Char(c) => RtPayload::Char(c),
459 WireValue::Text(s) => RtPayload::Text(s),
460 WireValue::Duration(n) => RtPayload::Duration(n),
461 WireValue::Date(n) => RtPayload::Date(n),
462 WireValue::Moment(n) => RtPayload::Moment(n),
463 WireValue::Span { months, days } => RtPayload::Span { months, days },
464 WireValue::Time(n) => RtPayload::Time(n),
465 WireValue::Word { width, bits } => RtPayload::Word { width, bits },
466 WireValue::Peer(topic) => RtPayload::Peer(topic),
467 WireValue::List(items) => RtPayload::List(items.into_iter().map(wire_to_rt).collect()),
468 WireValue::Tuple(items) => RtPayload::Tuple(items.into_iter().map(wire_to_rt).collect()),
469 WireValue::Set(items) => RtPayload::Set(items.into_iter().map(wire_to_rt).collect()),
470 WireValue::Map(pairs) => {
471 RtPayload::Map(pairs.into_iter().map(|(k, v)| (wire_to_rt(k), wire_to_rt(v))).collect())
472 }
473 WireValue::Struct { type_name, fields } => RtPayload::Struct {
474 type_name,
475 fields: fields.into_iter().map(|(n, v)| (n, wire_to_rt(v))).collect(),
476 },
477 WireValue::Inductive { type_name, constructor, args } => RtPayload::Inductive {
478 type_name,
479 constructor,
480 args: args.into_iter().map(wire_to_rt).collect(),
481 },
482 }
483}
484
485#[derive(Debug, Clone, Copy, PartialEq, Eq)]
495pub enum WireCodec {
496 Native,
498 Json,
500}
501
502#[derive(Debug, Clone, Copy, PartialEq, Eq)]
509pub enum WireIntegrity {
510 Raw,
512 Checked,
515}
516
517const H_CHECKED: u8 = 0x01;
521const H_COMPRESSED: u8 = 0x02;
522const H_CODEC: u8 = 0x0C; const H_JSON: u8 = 0x10;
524const H_KNOWN: u8 = H_CHECKED | H_COMPRESSED | H_CODEC | H_JSON;
525
526pub fn message_to_wire(from: &str, value: &RuntimeValue) -> Result<Vec<u8>, String> {
533 message_to_wire_with(from, value, WireCodec::Native, current_integrity())
534}
535
536pub fn encode_value_raw(v: &RuntimeValue) -> Result<Vec<u8>, String> {
542 with_flat_lists(true, || {
543 with_structure(WireStructure::Off, || {
544 with_dedup(false, || {
545 let mut out = Vec::new();
546 native_encode(v, &mut out)?;
547 Ok(out)
548 })
549 })
550 })
551}
552
553pub fn decode_value_raw(buf: &[u8]) -> Option<RuntimeValue> {
556 let mut pos = 0usize;
557 let v = native_decode(buf, &mut pos)?;
558 if pos == buf.len() {
559 Some(v)
560 } else {
561 None
562 }
563}
564
565#[derive(Clone, Copy, PartialEq, Eq, Debug)]
567pub enum WireGoal {
568 Smallest,
571 Fastest,
574}
575
576pub fn message_to_wire_best(from: &str, value: &RuntimeValue, goal: WireGoal) -> Result<Vec<u8>, String> {
588 match goal {
589 WireGoal::Fastest => with_numerics(WireNumerics::Fixed, || {
590 with_structure(WireStructure::Off, || {
591 with_floats(WireFloats::Memcpy, || {
592 with_compression_codec(WireCompression::None, || message_to_wire(from, value))
593 })
594 })
595 }),
596 WireGoal::Smallest => smallest_over(
597 from,
598 value,
599 &[WireCompression::None, WireCompression::Deflate, WireCompression::Lz4, WireCompression::Zstd],
600 ),
601 }
602}
603
604fn smallest_over(
610 from: &str,
611 value: &RuntimeValue,
612 compressions: &[WireCompression],
613) -> Result<Vec<u8>, String> {
614 let mut best: Option<Vec<u8>> = None;
615 let dedup_opts: &[bool] = if value_has_sharing(value) { &[false, true] } else { &[false] };
620 for num in [WireNumerics::Varint, WireNumerics::Fixed, WireNumerics::GroupVarint] {
621 for st in [WireStructure::Off, WireStructure::Affine, WireStructure::Auto] {
622 for fl in [WireFloats::Memcpy, WireFloats::XorDelta] {
623 for &comp in compressions {
624 for &dedup in dedup_opts {
625 let bytes = with_dedup(dedup, || {
626 with_numerics(num, || {
627 with_structure(st, || {
628 with_floats(fl, || {
629 with_compression_codec(comp, || message_to_wire(from, value))
630 })
631 })
632 })
633 })?;
634 if best.as_ref().map_or(true, |b| bytes.len() < b.len()) {
635 best = Some(bytes);
636 }
637 }
638 }
639 }
640 }
641 }
642 best.ok_or_else(|| "no encoding produced".to_string())
643}
644
645pub fn message_to_wire_negotiated(
653 from: &str,
654 value: &RuntimeValue,
655 neg: &Negotiated,
656 registry: WireTypeRegistry,
657) -> Result<Vec<u8>, String> {
658 if matches!(value, RuntimeValue::Function(_)) && !neg.may_send_computed {
659 return Err("the receiver does not accept computed (shipped-function) sends".to_string());
660 }
661 let default = message_to_wire(from, value)?;
662 if default.len() <= AUTO_SEARCH_THRESHOLD && !neg.use_type_id {
664 return Ok(default);
665 }
666 let codecs: Vec<WireCompression> = if neg.compression == WireCompression::None {
667 vec![WireCompression::None]
668 } else {
669 vec![WireCompression::None, neg.compression]
670 };
671 let search = || smallest_over(from, value, &codecs);
672 let best = if neg.use_type_id { with_type_registry(registry, search) } else { search() }?;
674 Ok(if best.len() < default.len() { best } else { default })
675}
676
677const AUTO_SEARCH_THRESHOLD: usize = 64;
681
682pub fn message_to_wire_auto(from: &str, value: &RuntimeValue) -> Result<Vec<u8>, String> {
688 let default = message_to_wire(from, value)?;
689 if default.len() <= AUTO_SEARCH_THRESHOLD {
690 return Ok(default);
691 }
692 let best = message_to_wire_best(from, value, WireGoal::Smallest)?;
694 Ok(if best.len() < default.len() { best } else { default })
695}
696
697#[derive(Clone, Copy, Debug, PartialEq, Eq)]
703pub struct ReceiveLimits {
704 pub max_bytes: usize,
706 pub max_depth: usize,
709 pub max_elements: usize,
712 pub max_string_bytes: usize,
714 pub accept_computed: bool,
718}
719
720pub const DEFAULT_RECEIVE_LIMITS: ReceiveLimits = ReceiveLimits {
726 max_bytes: 64 << 20,
727 max_depth: 64,
728 max_elements: 1 << 24,
729 max_string_bytes: 1 << 24,
730 accept_computed: true,
731};
732
733impl Default for ReceiveLimits {
734 fn default() -> Self {
735 DEFAULT_RECEIVE_LIMITS
736 }
737}
738
739thread_local! {
740 static RECEIVE_LIMITS: std::cell::Cell<ReceiveLimits> =
741 const { std::cell::Cell::new(DEFAULT_RECEIVE_LIMITS) };
742 static DECODE_DEPTH: std::cell::Cell<usize> = const { std::cell::Cell::new(0) };
743}
744
745pub fn with_receive_limits<T>(limits: ReceiveLimits, f: impl FnOnce() -> T) -> T {
748 let prev = RECEIVE_LIMITS.with(|c| c.replace(limits));
749 let r = f();
750 RECEIVE_LIMITS.with(|c| c.set(prev));
751 r
752}
753
754fn receive_limits() -> ReceiveLimits {
757 RECEIVE_LIMITS.with(std::cell::Cell::get)
758}
759
760pub const FEAT_DEFLATE: u32 = 1 << 0;
764pub const FEAT_LZ4: u32 = 1 << 1;
766pub const FEAT_ZSTD: u32 = 1 << 2;
768pub const FEAT_TYPE_ID: u32 = 1 << 3;
770pub const FEAT_COMPUTED: u32 = 1 << 4;
772pub const FEAT_FEC: u32 = 1 << 5;
774
775#[derive(Clone, Copy, Debug, PartialEq, Eq)]
782pub struct PeerProfile {
783 pub limits: ReceiveLimits,
785 pub registry_epoch: u64,
788 pub features: u32,
790}
791
792impl Default for PeerProfile {
793 fn default() -> Self {
794 Self {
795 limits: ReceiveLimits::default(),
796 registry_epoch: 0,
797 features: FEAT_DEFLATE | FEAT_LZ4 | FEAT_ZSTD | FEAT_TYPE_ID | FEAT_COMPUTED | FEAT_FEC,
798 }
799 }
800}
801
802impl PeerProfile {
803 pub const fn conservative() -> Self {
809 Self { limits: DEFAULT_RECEIVE_LIMITS, registry_epoch: 0, features: 0 }
810 }
811}
812
813const PEER_PROFILE_VERSION: u8 = 1;
814
815pub fn encode_peer_profile(p: &PeerProfile) -> Vec<u8> {
818 let mut out = Vec::with_capacity(32);
819 out.push(PEER_PROFILE_VERSION);
820 write_uvarint(p.limits.max_bytes as u64, &mut out);
821 write_uvarint(p.limits.max_depth as u64, &mut out);
822 write_uvarint(p.limits.max_elements as u64, &mut out);
823 write_uvarint(p.limits.max_string_bytes as u64, &mut out);
824 out.push(p.limits.accept_computed as u8);
825 write_uvarint(p.registry_epoch, &mut out);
826 write_uvarint(p.features as u64, &mut out);
827 out
828}
829
830pub fn decode_peer_profile(buf: &[u8]) -> Option<PeerProfile> {
833 let mut pos = 0;
834 let version = *buf.get(pos)?;
835 pos += 1;
836 if version != PEER_PROFILE_VERSION {
837 return None;
838 }
839 let max_bytes = read_uvarint(buf, &mut pos)? as usize;
840 let max_depth = read_uvarint(buf, &mut pos)? as usize;
841 let max_elements = read_uvarint(buf, &mut pos)? as usize;
842 let max_string_bytes = read_uvarint(buf, &mut pos)? as usize;
843 let accept_computed = *buf.get(pos)? != 0;
844 pos += 1;
845 let registry_epoch = read_uvarint(buf, &mut pos)?;
846 let features = read_uvarint(buf, &mut pos)? as u32;
847 Some(PeerProfile {
848 limits: ReceiveLimits { max_bytes, max_depth, max_elements, max_string_bytes, accept_computed },
849 registry_epoch,
850 features,
851 })
852}
853
854#[derive(Clone, Copy, Debug, PartialEq, Eq)]
856pub struct Negotiated {
857 pub use_type_id: bool,
860 pub may_send_computed: bool,
863 pub compression: WireCompression,
865 pub peer_max_bytes: usize,
867}
868
869pub fn negotiate(mine: &PeerProfile, theirs: &PeerProfile) -> Negotiated {
875 let both = |bit: u32| mine.features & bit != 0 && theirs.features & bit != 0;
876 let compression = if both(FEAT_ZSTD) {
877 WireCompression::Zstd
878 } else if both(FEAT_LZ4) {
879 WireCompression::Lz4
880 } else if both(FEAT_DEFLATE) {
881 WireCompression::Deflate
882 } else {
883 WireCompression::None
884 };
885 Negotiated {
886 use_type_id: both(FEAT_TYPE_ID)
887 && mine.registry_epoch != 0
888 && mine.registry_epoch == theirs.registry_epoch,
889 may_send_computed: theirs.limits.accept_computed && both(FEAT_COMPUTED),
890 compression,
891 peer_max_bytes: theirs.limits.max_bytes,
892 }
893}
894
895const HANDSHAKE_MAGIC: &[u8; 4] = b"LCHS";
899
900pub fn make_handshake_frame(from: &str, profile: &PeerProfile) -> Vec<u8> {
904 let mut out = Vec::with_capacity(8 + from.len() + 16);
905 out.extend_from_slice(HANDSHAKE_MAGIC);
906 write_str(from, &mut out);
907 out.extend_from_slice(&encode_peer_profile(profile));
908 out
909}
910
911pub fn parse_handshake_frame(data: &[u8]) -> Option<(String, PeerProfile)> {
915 let rest = data.strip_prefix(HANDSHAKE_MAGIC.as_slice())?;
916 let mut pos = 0;
917 let from = read_str(rest, &mut pos)?;
918 let profile = decode_peer_profile(rest.get(pos..)?)?;
919 Some((from, profile))
920}
921
922pub fn message_to_wire_with(
924 from: &str,
925 value: &RuntimeValue,
926 codec: WireCodec,
927 integrity: WireIntegrity,
928) -> Result<Vec<u8>, String> {
929 let mut body = match codec {
930 WireCodec::Native => {
932 let mut out = Vec::with_capacity(from.len() + 32);
935 write_str(from, &mut out);
936 native_encode(value, &mut out)?;
937 out
938 }
939 WireCodec::Json => {
941 let payload = materialize(value)
942 .map_err(|MarshalError::NotSendable(t)| format!("a {t} cannot be sent over the network"))?;
943 let msg = rt_to_wire(&payload)
944 .ok_or_else(|| "a channel or task handle cannot be sent over the network".to_string())?;
945 serde_json::to_vec(&WireMessage { from: from.to_string(), msg })
946 .map_err(|e| format!("message encode failed: {e}"))?
947 }
948 };
949 let mut compression = WireCompression::None;
952 if let Some((used, z)) = compress_body(compression_codec(), &body) {
953 if z.len() < body.len() {
954 body = z;
955 compression = used;
956 }
957 }
958 Ok(frame(codec, integrity, compression, body))
959}
960
961pub fn message_from_wire(bytes: &[u8]) -> Option<(String, RuntimeValue)> {
967 if bytes.len() > receive_limits().max_bytes {
970 return None;
971 }
972 DECODE_MEMO.with(|c| c.borrow_mut().clear());
974 let (codec, compression, framed) = unframe(bytes)?;
975 let inflated;
979 let body: &[u8] = if compression == WireCompression::None {
980 framed
981 } else {
982 inflated = decompress_body(compression, framed)?;
983 &inflated
984 };
985 match codec {
986 WireCodec::Native => {
987 let mut pos = 0;
988 let from = read_str(body, &mut pos)?;
989 let value = native_decode(body, &mut pos)?;
990 (pos == body.len()).then_some((from, value)) }
992 WireCodec::Json => {
993 let WireMessage { from, msg } = serde_json::from_slice(body).ok()?;
994 Some((from, rebuild(wire_to_rt(msg))))
995 }
996 }
997}
998
999fn column_tag_name(tag: u8) -> &'static str {
1003 match tag {
1004 T_INTS => "varint",
1005 T_INTS_FIXED => "fixed (memcpy)",
1006 T_INTS_GV => "group-varint",
1007 T_INTS_ALIGNED => "fixed-aligned",
1008 T_INTS_AFFINE => "affine (base,stride,n)",
1009 T_INTS_DELTA => "delta",
1010 T_INTS_DOD => "delta-of-delta",
1011 T_INTS_FOR => "FOR bit-pack",
1012 T_INTS_RLE => "run-length",
1013 T_INTS_DICT => "dictionary",
1014 T_INTS_POLY => "polynomial",
1015 T_INTS_GEOMETRIC => "geometric",
1016 T_INTS_PERIODIC => "periodic",
1017 T_INTS_SPARSE => "sparse",
1018 T_GEN => "generator",
1019 T_BYTES => "byte column",
1020 describe::T_INTS_LRECUR => "linear-recurrence",
1021 describe::T_INTS_LFSR => "LFSR",
1022 describe::T_INTS_FCSR => "FCSR",
1023 T_FLOATS => "memcpy floats",
1024 T_FLOATS_XOR => "xor-delta floats",
1025 T_FLOATS_CONST => "constant floats",
1026 T_FLOATS_AFFINE => "affine floats",
1027 T_FLOATS_SPARSE => "sparse floats",
1028 T_FLOATS_PERIODIC => "periodic floats",
1029 T_FLOATS_GEOMETRIC => "geometric floats",
1030 T_FLOATS_ALIGNED => "aligned floats",
1031 T_BOOLS => "bit-packed bools",
1032 T_BOOLS_PERIODIC => "periodic bools",
1033 T_BOOLS_RLE => "run-length bools",
1034 T_STRINGS => "flat strings",
1035 T_STRINGS_TEMPLATE => "templated strings",
1036 T_STRINGS_FRONT => "front-coded strings",
1037 T_STRINGS_AFFIX => "affix strings",
1038 T_STRINGS_DICT => "dictionary strings",
1039 T_SET_INTS => "int set (column menu)",
1040 T_SET_STRINGS => "string set (front-coded)",
1041 T_MAP_INTKEY => "int-keyed map (columnar)",
1042 _ => "value",
1043 }
1044}
1045
1046pub fn describe_columns(bytes: &[u8]) -> Vec<String> {
1054 describe_columns_inner(bytes).unwrap_or_default()
1055}
1056
1057fn describe_columns_inner(bytes: &[u8]) -> Option<Vec<String>> {
1058 let (codec, compression, body) = unframe(bytes)?;
1059 if !matches!(codec, WireCodec::Native) || compression != WireCompression::None {
1060 return None; }
1062 DECODE_MEMO.with(|c| c.borrow_mut().clear());
1063 let mut pos = 0;
1064 let _from = read_str(body, &mut pos)?;
1065 let tag = *body.get(pos)?;
1066 if tag == T_STRUCTS {
1067 let mut p = pos + 1;
1068 let (_type_name, field_names) = read_struct_schema(body, &mut p)?;
1069 let _rows = read_uvarint(body, &mut p)?;
1070 let mut out = Vec::with_capacity(field_names.len());
1071 for name in &field_names {
1072 let col_tag = *body.get(p)?;
1073 native_decode(body, &mut p)?; out.push(format!("{name}: {}", column_tag_name(col_tag)));
1075 }
1076 return Some(out);
1077 }
1078 Some(vec![column_tag_name(tag).to_string()])
1079}
1080
1081#[derive(Clone, Copy, PartialEq, Eq, Debug, Default)]
1084pub enum WireSchemaMode {
1085 #[default]
1087 Off,
1088 Sequential,
1092 ContentAddressed,
1098}
1099
1100#[derive(Debug)]
1108pub struct WireSchemaCache {
1109 mode: WireSchemaMode,
1110 send_seq: std::collections::HashMap<(String, Vec<String>), u32>,
1112 recv_seq: Vec<(String, Vec<String>)>,
1113 next: u32,
1114 send_ca: std::collections::HashSet<u64>,
1116 recv_ca: std::collections::HashMap<u64, (String, Vec<String>)>,
1117 keyframe: Option<u32>,
1119 refs_since_def: std::collections::HashMap<u64, u32>,
1120}
1121
1122impl Default for WireSchemaCache {
1123 fn default() -> Self {
1125 Self::with_mode(WireSchemaMode::ContentAddressed)
1126 }
1127}
1128
1129impl WireSchemaCache {
1130 fn with_mode(mode: WireSchemaMode) -> Self {
1131 Self {
1132 mode,
1133 send_seq: std::collections::HashMap::new(),
1134 recv_seq: Vec::new(),
1135 next: 0,
1136 send_ca: std::collections::HashSet::new(),
1137 recv_ca: std::collections::HashMap::new(),
1138 keyframe: None,
1139 refs_since_def: std::collections::HashMap::new(),
1140 }
1141 }
1142 pub fn content_addressed() -> Self {
1144 Self::with_mode(WireSchemaMode::ContentAddressed)
1145 }
1146 pub fn sequential() -> Self {
1148 Self::with_mode(WireSchemaMode::Sequential)
1149 }
1150 pub fn with_keyframe(mut self, k: u32) -> Self {
1153 self.keyframe = Some(k);
1154 self
1155 }
1156}
1157
1158fn schema_fingerprint(type_name: &str, field_names: &[String]) -> u64 {
1162 let mut bytes = Vec::with_capacity(type_name.len() + 8);
1163 bytes.extend_from_slice(type_name.as_bytes());
1164 for f in field_names {
1165 bytes.push(0);
1166 bytes.extend_from_slice(f.as_bytes());
1167 }
1168 fnv1a_64(&bytes)
1169}
1170
1171enum SchemaEmit {
1173 Inline,
1174 SeqDef(u32),
1175 SeqRef(u32),
1176 CaDef,
1177 CaRef(u64),
1178}
1179
1180thread_local! {
1181 static SCHEMA_CACHE: RefCell<Option<WireSchemaCache>> = const { RefCell::new(None) };
1184}
1185
1186struct CacheScope<'a> {
1190 cache: &'a mut WireSchemaCache,
1191}
1192impl<'a> CacheScope<'a> {
1193 fn enter(cache: &'a mut WireSchemaCache) -> Self {
1194 SCHEMA_CACHE.with(|c| *c.borrow_mut() = Some(std::mem::take(cache)));
1195 Self { cache }
1196 }
1197}
1198impl Drop for CacheScope<'_> {
1199 fn drop(&mut self) {
1200 SCHEMA_CACHE.with(|c| *self.cache = c.borrow_mut().take().unwrap_or_default());
1201 }
1202}
1203
1204pub fn message_to_wire_cached(
1207 from: &str,
1208 value: &RuntimeValue,
1209 codec: WireCodec,
1210 integrity: WireIntegrity,
1211 cache: &mut WireSchemaCache,
1212) -> Result<Vec<u8>, String> {
1213 let _scope = CacheScope::enter(cache);
1214 message_to_wire_with(from, value, codec, integrity)
1215}
1216
1217pub fn message_from_wire_cached(bytes: &[u8], cache: &mut WireSchemaCache) -> Option<(String, RuntimeValue)> {
1220 let _scope = CacheScope::enter(cache);
1221 message_from_wire(bytes)
1222}
1223
1224fn schema_send(type_name: &str, field_names: &[String]) -> SchemaEmit {
1226 SCHEMA_CACHE.with(|c| {
1227 let mut g = c.borrow_mut();
1228 let Some(cache) = g.as_mut() else { return SchemaEmit::Inline };
1229 match cache.mode {
1230 WireSchemaMode::Off => SchemaEmit::Inline,
1231 WireSchemaMode::Sequential => {
1232 let key = (type_name.to_string(), field_names.to_vec());
1233 if let Some(&id) = cache.send_seq.get(&key) {
1234 SchemaEmit::SeqRef(id)
1235 } else {
1236 let id = cache.next;
1237 cache.next += 1;
1238 cache.send_seq.insert(key, id);
1239 SchemaEmit::SeqDef(id)
1240 }
1241 }
1242 WireSchemaMode::ContentAddressed => {
1243 let fp = schema_fingerprint(type_name, field_names);
1244 let known = cache.send_ca.contains(&fp);
1245 let count = cache.refs_since_def.entry(fp).or_insert(0);
1246 let keyframe_due = matches!(cache.keyframe, Some(k) if known && *count >= k);
1247 if known && !keyframe_due {
1248 *count += 1;
1249 SchemaEmit::CaRef(fp)
1250 } else {
1251 *count = 0;
1252 cache.send_ca.insert(fp);
1253 SchemaEmit::CaDef
1254 }
1255 }
1256 }
1257 })
1258}
1259
1260fn schema_recv_register_seq(id: u32, type_name: &str, field_names: &[String]) -> bool {
1264 SCHEMA_CACHE.with(|c| {
1265 let mut g = c.borrow_mut();
1266 let Some(cache) = g.as_mut() else { return true };
1267 let entry = (type_name.to_string(), field_names.to_vec());
1268 let idx = id as usize;
1269 if idx == cache.recv_seq.len() {
1270 cache.recv_seq.push(entry);
1271 true
1272 } else if idx < cache.recv_seq.len() {
1273 cache.recv_seq[idx] == entry
1274 } else {
1275 false
1276 }
1277 })
1278}
1279
1280fn schema_recv_lookup_seq(id: u32) -> Option<(String, Vec<String>)> {
1282 SCHEMA_CACHE.with(|c| c.borrow().as_ref().and_then(|cache| cache.recv_seq.get(id as usize).cloned()))
1283}
1284
1285fn schema_recv_register_ca(type_name: &str, field_names: &[String]) -> bool {
1289 SCHEMA_CACHE.with(|c| {
1290 let mut g = c.borrow_mut();
1291 let Some(cache) = g.as_mut() else { return true };
1292 let fp = schema_fingerprint(type_name, field_names);
1293 let entry = (type_name.to_string(), field_names.to_vec());
1294 match cache.recv_ca.get(&fp) {
1295 Some(existing) => *existing == entry, None => {
1297 cache.recv_ca.insert(fp, entry);
1298 true
1299 }
1300 }
1301 })
1302}
1303
1304fn schema_recv_lookup_ca(fp: u64) -> Option<(String, Vec<String>)> {
1307 SCHEMA_CACHE.with(|c| c.borrow().as_ref().and_then(|cache| cache.recv_ca.get(&fp).cloned()))
1308}
1309
1310#[derive(Debug, Default, Clone)]
1317pub struct WireTypeRegistry {
1318 by_id: Vec<(String, Vec<String>)>,
1319 by_fp: std::collections::HashMap<u64, u32>,
1320 enums_by_id: Vec<(String, Vec<String>)>,
1323 enums_by_name: std::collections::HashMap<String, u32>,
1324}
1325
1326impl WireTypeRegistry {
1327 pub fn new(schemas: Vec<(String, Vec<String>)>) -> Self {
1331 let mut canon: Vec<(String, Vec<String>)> = schemas
1332 .into_iter()
1333 .map(|(n, mut f)| {
1334 f.sort();
1335 (n, f)
1336 })
1337 .collect();
1338 canon.sort_by_key(|(n, f)| schema_fingerprint(n, f));
1339 canon.dedup_by_key(|(n, f)| schema_fingerprint(n, f));
1340 let by_fp = canon
1341 .iter()
1342 .enumerate()
1343 .map(|(i, (n, f))| (schema_fingerprint(n, f), i as u32))
1344 .collect();
1345 Self { by_id: canon, by_fp, ..Self::default() }
1346 }
1347
1348 pub fn with_enums(mut self, enums: Vec<(String, Vec<String>)>) -> Self {
1352 let mut canon = enums;
1353 canon.sort_by_key(|(n, c)| schema_fingerprint(n, c));
1354 canon.dedup_by_key(|(n, c)| schema_fingerprint(n, c));
1355 self.enums_by_name = canon
1356 .iter()
1357 .enumerate()
1358 .map(|(i, (n, _))| (n.clone(), i as u32))
1359 .collect();
1360 self.enums_by_id = canon;
1361 self
1362 }
1363
1364 pub fn epoch(&self) -> u64 {
1370 if self.by_id.is_empty() && self.enums_by_id.is_empty() {
1371 return 0;
1372 }
1373 let mut acc: u64 = 0xcbf2_9ce4_8422_2325;
1374 for (n, f) in &self.by_id {
1375 acc = acc.rotate_left(5) ^ schema_fingerprint(n, f);
1376 }
1377 for (n, c) in &self.enums_by_id {
1378 acc = acc.rotate_left(7) ^ schema_fingerprint(n, c).wrapping_mul(0x0000_0100_0000_01b3);
1379 }
1380 acc.max(1) }
1382
1383 fn id_of(&self, type_name: &str, field_names: &[String]) -> Option<u32> {
1384 self.by_fp.get(&schema_fingerprint(type_name, field_names)).copied()
1385 }
1386 fn schema_of(&self, id: u32) -> Option<(String, Vec<String>)> {
1387 self.by_id.get(id as usize).cloned()
1388 }
1389 fn enum_id_of(&self, type_name: &str, constructor: &str) -> Option<(u32, u32)> {
1391 let id = *self.enums_by_name.get(type_name)?;
1392 let (_, ctors) = self.enums_by_id.get(id as usize)?;
1393 let idx = ctors.iter().position(|c| c == constructor)? as u32;
1394 Some((id, idx))
1395 }
1396 fn enum_schema_of(&self, id: u32) -> Option<(String, Vec<String>)> {
1398 self.enums_by_id.get(id as usize).cloned()
1399 }
1400}
1401
1402thread_local! {
1403 static TYPE_REGISTRY: RefCell<Option<WireTypeRegistry>> = const { RefCell::new(None) };
1404}
1405
1406pub fn with_type_registry<T>(reg: WireTypeRegistry, f: impl FnOnce() -> T) -> T {
1409 struct Restore(Option<WireTypeRegistry>);
1410 impl Drop for Restore {
1411 fn drop(&mut self) {
1412 TYPE_REGISTRY.with(|c| *c.borrow_mut() = self.0.take());
1413 }
1414 }
1415 let _restore = Restore(TYPE_REGISTRY.with(|c| c.borrow_mut().replace(reg)));
1416 f()
1417}
1418
1419fn type_registry_id(type_name: &str, field_names: &[String]) -> Option<u32> {
1421 TYPE_REGISTRY.with(|c| c.borrow().as_ref().and_then(|r| r.id_of(type_name, field_names)))
1422}
1423
1424fn type_registry_schema(id: u32) -> Option<(String, Vec<String>)> {
1426 TYPE_REGISTRY.with(|c| c.borrow().as_ref().and_then(|r| r.schema_of(id)))
1427}
1428
1429fn type_registry_enum_id(type_name: &str, constructor: &str) -> Option<(u32, u32)> {
1431 TYPE_REGISTRY.with(|c| c.borrow().as_ref().and_then(|r| r.enum_id_of(type_name, constructor)))
1432}
1433
1434fn type_registry_enum_schema(id: u32) -> Option<(String, Vec<String>)> {
1436 TYPE_REGISTRY.with(|c| c.borrow().as_ref().and_then(|r| r.enum_schema_of(id)))
1437}
1438
1439thread_local! {
1440 static DEDUP_ENABLED: std::cell::Cell<bool> = const { std::cell::Cell::new(false) };
1446 static ENCODE_SHARED: RefCell<Option<std::collections::HashSet<usize>>> = const { RefCell::new(None) };
1449 static ENCODE_WRITTEN: RefCell<std::collections::HashMap<usize, u64>> =
1451 RefCell::new(std::collections::HashMap::new());
1452 static DECODE_MEMO: RefCell<std::collections::HashMap<u64, RuntimeValue>> =
1455 RefCell::new(std::collections::HashMap::new());
1456}
1457
1458pub fn with_dedup<T>(enabled: bool, f: impl FnOnce() -> T) -> T {
1461 let prev = DEDUP_ENABLED.with(|c| c.replace(enabled));
1462 ENCODE_SHARED.with(|c| *c.borrow_mut() = None);
1463 ENCODE_WRITTEN.with(|c| c.borrow_mut().clear());
1464 let r = f();
1465 DEDUP_ENABLED.with(|c| c.set(prev));
1466 ENCODE_SHARED.with(|c| *c.borrow_mut() = None);
1467 ENCODE_WRITTEN.with(|c| c.borrow_mut().clear());
1468 r
1469}
1470
1471fn shareable_ptr(v: &RuntimeValue) -> Option<usize> {
1475 match v {
1476 RuntimeValue::List(rc) => Some(Rc::as_ptr(rc) as *const () as usize),
1477 RuntimeValue::Tuple(rc) => Some(Rc::as_ptr(rc) as *const () as usize),
1478 RuntimeValue::Set(rc) => Some(Rc::as_ptr(rc) as *const () as usize),
1479 RuntimeValue::Map(rc) => Some(Rc::as_ptr(rc) as *const () as usize),
1480 RuntimeValue::Text(rc) => Some(Rc::as_ptr(rc) as *const () as usize),
1481 RuntimeValue::BigInt(rc) => Some(Rc::as_ptr(rc) as *const () as usize),
1482 RuntimeValue::Rational(rc) => Some(Rc::as_ptr(rc) as *const () as usize),
1483 RuntimeValue::Decimal(rc) => Some(Rc::as_ptr(rc) as *const () as usize),
1484 RuntimeValue::Money(rc) => Some(Rc::as_ptr(rc) as *const () as usize),
1485 RuntimeValue::Complex(rc) => Some(Rc::as_ptr(rc) as *const () as usize),
1486 RuntimeValue::Modular(rc) => Some(Rc::as_ptr(rc) as *const () as usize),
1487 RuntimeValue::Quantity(rc) => Some(Rc::as_ptr(rc) as *const () as usize),
1488 _ => None,
1489 }
1490}
1491
1492fn gather_shared(
1497 v: &RuntimeValue,
1498 seen: &mut std::collections::HashMap<usize, u32>,
1499 shared: &mut std::collections::HashSet<usize>,
1500 depth: u32,
1501) {
1502 if depth >= MAX_ENCODE_DEPTH {
1503 return;
1504 }
1505 if let Some(p) = shareable_ptr(v) {
1506 let c = seen.entry(p).or_insert(0);
1507 *c += 1;
1508 if *c >= 2 {
1509 shared.insert(p);
1510 return; }
1512 }
1513 match v {
1514 RuntimeValue::List(rc) => {
1515 if let ListRepr::Boxed(items) = &*rc.borrow() {
1516 for x in items {
1517 gather_shared(x, seen, shared, depth + 1);
1518 }
1519 }
1520 }
1521 RuntimeValue::Tuple(rc) => {
1522 for x in rc.iter() {
1523 gather_shared(x, seen, shared, depth + 1);
1524 }
1525 }
1526 RuntimeValue::Set(rc) => {
1527 for x in rc.borrow().iter() {
1528 gather_shared(x, seen, shared, depth + 1);
1529 }
1530 }
1531 RuntimeValue::Map(rc) => {
1532 for (k, val) in rc.borrow().iter() {
1533 gather_shared(k, seen, shared, depth + 1);
1534 gather_shared(val, seen, shared, depth + 1);
1535 }
1536 }
1537 RuntimeValue::Struct(b) => {
1538 for val in b.fields.values() {
1539 gather_shared(val, seen, shared, depth + 1);
1540 }
1541 }
1542 RuntimeValue::Inductive(b) => {
1543 for x in &b.args {
1544 gather_shared(x, seen, shared, depth + 1);
1545 }
1546 }
1547 _ => {}
1548 }
1549}
1550
1551fn value_has_sharing(v: &RuntimeValue) -> bool {
1555 let mut seen = std::collections::HashMap::new();
1556 let mut shared = std::collections::HashSet::new();
1557 gather_shared(v, &mut seen, &mut shared, 0);
1558 !shared.is_empty()
1559}
1560
1561fn dedup_encode_prefix(v: &RuntimeValue, out: &mut Vec<u8>) -> bool {
1566 if !DEDUP_ENABLED.with(|c| c.get()) {
1567 return false;
1568 }
1569 if ENCODE_SHARED.with(|c| c.borrow().is_none()) {
1570 let mut seen = std::collections::HashMap::new();
1571 let mut shared = std::collections::HashSet::new();
1572 gather_shared(v, &mut seen, &mut shared, 0);
1573 ENCODE_SHARED.with(|c| *c.borrow_mut() = Some(shared));
1574 ENCODE_WRITTEN.with(|c| c.borrow_mut().clear());
1575 }
1576 let Some(p) = shareable_ptr(v) else { return false };
1577 let is_shared = ENCODE_SHARED.with(|c| c.borrow().as_ref().is_some_and(|s| s.contains(&p)));
1578 if !is_shared {
1579 return false;
1580 }
1581 if let Some(id) = ENCODE_WRITTEN.with(|c| c.borrow().get(&p).copied()) {
1582 out.push(T_SHARED_REF);
1583 write_uvarint(id, out);
1584 return true; }
1586 let id = ENCODE_WRITTEN.with(|c| {
1587 let mut m = c.borrow_mut();
1588 let id = m.len() as u64;
1589 m.insert(p, id);
1590 id
1591 });
1592 out.push(T_SHARED_DEF);
1593 write_uvarint(id, out);
1594 false }
1596
1597thread_local! {
1598 static STRUCT_VIEW: std::cell::Cell<bool> = const { std::cell::Cell::new(false) };
1599 static ENCODE_DEPTH: std::cell::Cell<u32> = const { std::cell::Cell::new(0) };
1603}
1604
1605const MAX_ENCODE_DEPTH: u32 = 128;
1610
1611struct DepthGuard;
1614impl DepthGuard {
1615 fn enter() -> Result<DepthGuard, String> {
1616 ENCODE_DEPTH.with(|d| {
1617 let n = d.get();
1618 if n >= MAX_ENCODE_DEPTH {
1619 return Err(format!(
1620 "value nested deeper than {MAX_ENCODE_DEPTH} (cyclic or pathological) — not encodable"
1621 ));
1622 }
1623 d.set(n + 1);
1624 Ok(DepthGuard)
1625 })
1626 }
1627}
1628impl Drop for DepthGuard {
1629 fn drop(&mut self) {
1630 ENCODE_DEPTH.with(|d| d.set(d.get().saturating_sub(1)));
1631 }
1632}
1633
1634struct DecodeDepthGuard;
1640impl DecodeDepthGuard {
1641 fn enter() -> Option<DecodeDepthGuard> {
1642 DECODE_DEPTH.with(|d| {
1643 let n = d.get();
1644 if n >= receive_limits().max_depth {
1645 return None;
1646 }
1647 d.set(n + 1);
1648 Some(DecodeDepthGuard)
1649 })
1650 }
1651}
1652impl Drop for DecodeDepthGuard {
1653 fn drop(&mut self) {
1654 DECODE_DEPTH.with(|d| d.set(d.get().saturating_sub(1)));
1655 }
1656}
1657
1658pub fn with_struct_view<T>(on: bool, f: impl FnOnce() -> T) -> T {
1662 let prev = STRUCT_VIEW.with(|c| c.replace(on));
1663 let out = f();
1664 STRUCT_VIEW.with(|c| c.set(prev));
1665 out
1666}
1667
1668fn struct_view_on() -> bool {
1669 STRUCT_VIEW.with(std::cell::Cell::get)
1670}
1671
1672fn skip_str(buf: &[u8], pos: &mut usize) -> Option<()> {
1689 let n = read_uvarint(buf, pos)? as usize;
1690 let end = pos.checked_add(n)?;
1691 if end > buf.len() {
1692 return None;
1693 }
1694 *pos = end;
1695 Some(())
1696}
1697
1698pub fn peek_deferrable_sender(bytes: &[u8]) -> Option<String> {
1711 let view = view_message(bytes)?;
1712 let deferrable =
1713 view.structs_schema().is_some() || matches!(view.tag(), Some(T_INTS_ALIGNED) | Some(T_FLOATS_ALIGNED));
1714 if !deferrable {
1715 return None;
1716 }
1717 let (_, _, body) = unframe_with(bytes, false)?;
1718 let mut p = 0;
1719 read_str(body, &mut p)
1720}
1721
1722pub fn message_from_wire_view(bytes: &[u8]) -> Option<(String, RuntimeValue)> {
1723 if view_message(bytes).and_then(|v| v.structs_schema()).is_some() {
1725 let (_, _, body) = unframe_with(bytes, false)?;
1726 let mut p = 0;
1727 let sender = read_str(body, &mut p)?; let lazy = crate::interpreter::ListRepr::from_record_list_view(Rc::new(bytes.to_vec()))?;
1729 return Some((sender, RuntimeValue::List(Rc::new(RefCell::new(lazy)))));
1730 }
1731 message_from_wire(bytes)
1732}
1733
1734const STREAM_MAGIC: u8 = 0xFD;
1738
1739pub fn frame_stream_message(from: &str, values: &[RuntimeValue]) -> Result<Vec<u8>, String> {
1745 let mut out = vec![STREAM_MAGIC];
1746 write_str(from, &mut out);
1747 for v in values {
1748 let elem = message_to_wire("", v)?;
1749 crate::concurrency::stream::frame_for_stream(&elem, &mut out);
1750 }
1751 Ok(out)
1752}
1753
1754pub fn peek_stream_sender(bytes: &[u8]) -> Option<String> {
1757 if bytes.first() != Some(&STREAM_MAGIC) {
1758 return None;
1759 }
1760 let mut p = 1;
1761 read_str(bytes, &mut p)
1762}
1763
1764pub fn deframe_stream_message(bytes: &[u8]) -> Option<Vec<RuntimeValue>> {
1767 if bytes.first() != Some(&STREAM_MAGIC) {
1768 return None;
1769 }
1770 let mut p = 1;
1771 read_str(bytes, &mut p)?;
1772 let mut deframer = crate::concurrency::stream::StreamDeframer::new();
1773 deframer.push(bytes.get(p..)?);
1774 let mut values = Vec::new();
1775 deframer.drain_frames(|frame| {
1776 if let Some((_, v)) = message_from_wire(frame) {
1777 values.push(v);
1778 }
1779 });
1780 Some(values)
1781}
1782
1783#[derive(Clone, Copy)]
1786pub struct WireView<'a> {
1787 val: &'a [u8],
1789}
1790
1791pub fn view_message(bytes: &[u8]) -> Option<WireView<'_>> {
1795 let (codec, compression, body) = unframe_with(bytes, false)?;
1800 if !matches!(codec, WireCodec::Native) || compression != WireCompression::None {
1801 return None;
1802 }
1803 let mut pos = 0;
1804 skip_str(body, &mut pos)?; Some(WireView { val: body.get(pos..)? })
1806}
1807
1808impl<'a> WireView<'a> {
1809 fn tag(&self) -> Option<u8> {
1810 self.val.first().copied()
1811 }
1812
1813 pub fn as_int(&self) -> Option<i64> {
1815 if self.tag()? != T_INT {
1816 return None;
1817 }
1818 let mut p = 1;
1819 Some(unzigzag(read_uvarint(self.val, &mut p)?))
1820 }
1821
1822 pub fn as_float(&self) -> Option<f64> {
1824 if self.tag()? != T_FLOAT {
1825 return None;
1826 }
1827 let b = self.val.get(1..9)?;
1828 Some(f64::from_le_bytes(b.try_into().ok()?))
1829 }
1830
1831 pub fn struct_field(&self, name: &str) -> Option<WireView<'a>> {
1836 if self.tag()? != T_STRUCT_VIEW {
1837 return None;
1838 }
1839 let mut p = 1;
1840 skip_str(self.val, &mut p)?; let count = read_uvarint(self.val, &mut p)? as usize;
1842 let mut idx = None;
1843 for i in 0..count {
1844 let nlen = read_uvarint(self.val, &mut p)? as usize;
1845 let nbytes = self.val.get(p..p.checked_add(nlen)?)?;
1846 if nbytes == name.as_bytes() {
1847 idx = Some(i);
1848 }
1849 p += nlen;
1850 }
1851 let idx = idx?;
1852 let table_pos = p;
1853 let off_at = table_pos.checked_add(idx.checked_mul(4)?)?;
1854 let off_bytes = self.val.get(off_at..off_at.checked_add(4)?)?;
1855 let offset = u32::from_le_bytes(off_bytes.try_into().ok()?) as usize;
1856 let values_start = table_pos.checked_add(count.checked_mul(4)?)?;
1857 Some(WireView { val: self.val.get(values_start.checked_add(offset)?..)? })
1858 }
1859
1860 pub fn as_i64_slice(&self) -> Option<&'a [i64]> {
1865 if self.tag()? != T_INTS_ALIGNED {
1866 return None;
1867 }
1868 let mut p = 1;
1869 let n = read_uvarint(self.val, &mut p)? as usize;
1870 let pad = *self.val.get(p)? as usize;
1871 p += 1 + pad;
1872 let nbytes = n.checked_mul(8)?;
1873 let blob = self.val.get(p..p.checked_add(nbytes)?)?;
1874 if blob.as_ptr() as usize % 8 != 0 {
1875 return None; }
1877 Some(unsafe { std::slice::from_raw_parts(blob.as_ptr().cast::<i64>(), n) })
1880 }
1881
1882 pub fn as_f64_slice(&self) -> Option<&'a [f64]> {
1886 if self.tag()? != T_FLOATS_ALIGNED {
1887 return None;
1888 }
1889 let mut p = 1;
1890 let n = read_uvarint(self.val, &mut p)? as usize;
1891 let pad = *self.val.get(p)? as usize;
1892 p += 1 + pad;
1893 let nbytes = n.checked_mul(8)?;
1894 let blob = self.val.get(p..p.checked_add(nbytes)?)?;
1895 if blob.as_ptr() as usize % 8 != 0 {
1896 return None; }
1898 Some(unsafe { std::slice::from_raw_parts(blob.as_ptr().cast::<f64>(), n) })
1901 }
1902
1903 pub fn structs_fixed_i64_col(&self, fi: usize) -> Option<&'a [u8]> {
1910 if self.tag()? != T_STRUCTS {
1911 return None;
1912 }
1913 let mut p = 1;
1914 skip_str(self.val, &mut p)?; let k = read_uvarint(self.val, &mut p)? as usize;
1916 if fi >= k {
1917 return None;
1918 }
1919 for _ in 0..k {
1920 skip_str(self.val, &mut p)?; }
1922 let n = read_uvarint(self.val, &mut p)? as usize;
1923 for c in 0..=fi {
1924 if *self.val.get(p)? != T_INTS_FIXED {
1925 return None; }
1927 p += 1;
1928 let cnt = read_uvarint(self.val, &mut p)? as usize;
1929 if cnt != n {
1930 return None;
1931 }
1932 let nbytes = n.checked_mul(8)?;
1933 let blob = self.val.get(p..p.checked_add(nbytes)?)?;
1934 if c == fi {
1935 return Some(blob);
1936 }
1937 p += nbytes;
1938 }
1939 None
1940 }
1941
1942 pub fn as_byte_slice(&self) -> Option<&'a [u8]> {
1948 if self.tag()? != T_BYTES {
1949 return None;
1950 }
1951 let mut p = 1;
1952 let n = read_uvarint(self.val, &mut p)? as usize;
1953 self.val.get(p..p.checked_add(n)?)
1954 }
1955
1956 pub fn structs_len(&self) -> Option<usize> {
1959 let tag = self.tag()?;
1960 if tag != T_STRUCTS_VIEW && tag != T_STRUCTS_FVIEW {
1961 return None;
1962 }
1963 let mut p = 1;
1964 skip_str(self.val, &mut p)?; let f = read_uvarint(self.val, &mut p)? as usize;
1966 for _ in 0..f {
1967 let nlen = read_uvarint(self.val, &mut p)? as usize;
1968 p = p.checked_add(nlen)?;
1969 }
1970 if tag == T_STRUCTS_FVIEW {
1971 p = p.checked_add(f)?; }
1973 Some(read_uvarint(self.val, &mut p)? as usize)
1974 }
1975
1976 pub fn structs_row_field(&self, row: usize, name: &str) -> Option<WireView<'a>> {
1983 if self.tag()? != T_STRUCTS_VIEW {
1984 return None;
1985 }
1986 let mut p = 1;
1987 skip_str(self.val, &mut p)?; let f = read_uvarint(self.val, &mut p)? as usize;
1989 let mut field_idx = None;
1990 for i in 0..f {
1991 let nlen = read_uvarint(self.val, &mut p)? as usize;
1992 let nbytes = self.val.get(p..p.checked_add(nlen)?)?;
1993 if nbytes == name.as_bytes() {
1994 field_idx = Some(i);
1995 }
1996 p += nlen;
1997 }
1998 let fi = field_idx?;
1999 let n = read_uvarint(self.val, &mut p)? as usize;
2000 if row >= n {
2001 return None;
2002 }
2003 let row_table_pos = p;
2004 let rows_start = row_table_pos.checked_add(n.checked_mul(4)?)?;
2005 let row_off_at = row_table_pos.checked_add(row.checked_mul(4)?)?;
2006 let row_off =
2007 u32::from_le_bytes(self.val.get(row_off_at..row_off_at.checked_add(4)?)?.try_into().ok()?) as usize;
2008 let field_table_pos = rows_start.checked_add(row_off)?;
2009 let values_start = field_table_pos.checked_add(f.checked_mul(4)?)?;
2010 let field_off_at = field_table_pos.checked_add(fi.checked_mul(4)?)?;
2011 let field_off =
2012 u32::from_le_bytes(self.val.get(field_off_at..field_off_at.checked_add(4)?)?.try_into().ok()?) as usize;
2013 Some(WireView { val: self.val.get(values_start.checked_add(field_off)?..)? })
2014 }
2015
2016 pub fn structs_row_field_value(&self, row: usize, name: &str) -> Option<RuntimeValue> {
2023 match self.tag()? {
2024 T_STRUCTS_VIEW => self.structs_row_field(row, name)?.decode(),
2025 T_STRUCTS_FVIEW => {
2026 let mut p = 1;
2027 skip_str(self.val, &mut p)?; let f = read_uvarint(self.val, &mut p)? as usize;
2029 let mut field_idx = None;
2030 for i in 0..f {
2031 let nlen = read_uvarint(self.val, &mut p)? as usize;
2032 let nbytes = self.val.get(p..p.checked_add(nlen)?)?;
2033 if nbytes == name.as_bytes() {
2034 field_idx = Some(i);
2035 }
2036 p += nlen;
2037 }
2038 let fi = field_idx?;
2039 let kinds = self.val.get(p..p.checked_add(f)?)?;
2040 p += f;
2041 let n = read_uvarint(self.val, &mut p)? as usize;
2042 if row >= n {
2043 return None;
2044 }
2045 let (offsets, stride) = fview_layout(kinds);
2046 let rows_start = p;
2047 let cell_pos = rows_start.checked_add(row.checked_mul(stride)?)?.checked_add(offsets[fi])?;
2048 let mut bp = rows_start.checked_add(n.checked_mul(stride)?)?;
2050 let blob_len = read_uvarint(self.val, &mut bp)? as usize;
2051 let blob = self.val.get(bp..bp.checked_add(blob_len)?)?;
2052 fview_read_cell(kinds[fi], self.val.get(cell_pos..)?, blob)
2053 }
2054 _ => None,
2055 }
2056 }
2057
2058 pub fn decode(&self) -> Option<RuntimeValue> {
2063 let mut p = 0;
2064 native_decode(self.val, &mut p)
2065 }
2066
2067 pub fn structs_schema(&self) -> Option<(String, Vec<String>, usize)> {
2072 let tag = self.tag()?;
2073 if tag != T_STRUCTS_VIEW && tag != T_STRUCTS_FVIEW {
2074 return None;
2075 }
2076 let mut p = 1;
2077 let type_name = read_str(self.val, &mut p)?;
2078 let f = read_uvarint(self.val, &mut p)? as usize;
2079 let mut field_names = Vec::with_capacity(f);
2080 for _ in 0..f {
2081 field_names.push(read_str(self.val, &mut p)?);
2082 }
2083 if tag == T_STRUCTS_FVIEW {
2084 p = p.checked_add(f)?; }
2086 let n = read_uvarint(self.val, &mut p)? as usize;
2087 Some((type_name, field_names, n))
2088 }
2089
2090 pub fn as_bool(&self) -> Option<bool> {
2092 match self.tag()? {
2093 T_TRUE => Some(true),
2094 T_FALSE => Some(false),
2095 _ => None,
2096 }
2097 }
2098
2099 pub fn int_list_len(&self) -> Option<usize> {
2101 let mut p = 1;
2102 match self.tag()? {
2103 T_INTS_FIXED => Some(read_uvarint(self.val, &mut p)? as usize),
2104 T_INTS => Some((read_uvarint(self.val, &mut p)? >> 1) as usize),
2105 _ => None,
2106 }
2107 }
2108
2109 pub fn int_list_get(&self, i: usize) -> Option<i64> {
2112 match self.tag()? {
2113 T_INTS_FIXED => {
2114 let mut p = 1;
2115 let n = read_uvarint(self.val, &mut p)? as usize;
2116 if i >= n {
2117 return None;
2118 }
2119 let off = p + i * 8; let b = self.val.get(off..off + 8)?;
2121 Some(i64::from_le_bytes(b.try_into().ok()?))
2122 }
2123 T_INTS => {
2124 let mut p = 1;
2125 let header = read_uvarint(self.val, &mut p)?;
2126 let signed = header & 1 == 1;
2127 let n = (header >> 1) as usize;
2128 if i >= n {
2129 return None;
2130 }
2131 for _ in 0..i {
2132 read_uvarint(self.val, &mut p)?;
2133 }
2134 let u = read_uvarint(self.val, &mut p)?;
2135 Some(if signed { unzigzag(u) } else { u as i64 })
2136 }
2137 _ => None,
2138 }
2139 }
2140
2141 pub fn float_list_len(&self) -> Option<usize> {
2143 if self.tag()? != T_FLOATS {
2144 return None;
2145 }
2146 let mut p = 1;
2147 Some(read_uvarint(self.val, &mut p)? as usize)
2148 }
2149
2150 pub fn float_list_get(&self, i: usize) -> Option<f64> {
2152 if self.tag()? != T_FLOATS {
2153 return None;
2154 }
2155 let mut p = 1;
2156 let n = read_uvarint(self.val, &mut p)? as usize;
2157 if i >= n {
2158 return None;
2159 }
2160 let off = p + i * 8;
2161 let b = self.val.get(off..off + 8)?;
2162 Some(f64::from_le_bytes(b.try_into().ok()?))
2163 }
2164
2165 pub fn structs_cursor(&self) -> Option<WireStructsCursor<'a>> {
2170 let tag = self.tag()?;
2171 if tag != T_STRUCTS_VIEW && tag != T_STRUCTS_FVIEW {
2172 return None;
2173 }
2174 let val = self.val;
2175 let mut p = 1;
2176 let tn_len = read_uvarint(val, &mut p)? as usize; p = p.checked_add(tn_len)?;
2178 let f = read_uvarint(val, &mut p)? as usize;
2179 let mut field_names = Vec::with_capacity(f);
2180 for _ in 0..f {
2181 let nlen = read_uvarint(val, &mut p)? as usize;
2182 field_names.push(val.get(p..p.checked_add(nlen)?)?);
2183 p += nlen;
2184 }
2185 if tag == T_STRUCTS_FVIEW {
2186 let field_kinds = val.get(p..p.checked_add(f)?)?;
2187 p += f;
2188 let n = read_uvarint(val, &mut p)? as usize;
2189 let (field_offsets, stride) = fview_layout(field_kinds);
2190 let rows_start = p;
2191 let mut bp = rows_start.checked_add(n.checked_mul(stride)?)?;
2192 let blob_len = read_uvarint(val, &mut bp)? as usize;
2193 let blob = val.get(bp..bp.checked_add(blob_len)?)?;
2194 Some(WireStructsCursor {
2195 val,
2196 field_names,
2197 n,
2198 kind: CursorKind::Fixed { field_kinds, field_offsets, stride, rows_start, blob },
2199 })
2200 } else {
2201 let n = read_uvarint(val, &mut p)? as usize;
2202 let row_table_pos = p;
2203 let rows_start = row_table_pos.checked_add(n.checked_mul(4)?)?;
2204 Some(WireStructsCursor { val, field_names, n, kind: CursorKind::Variable { row_table_pos, rows_start } })
2205 }
2206 }
2207}
2208
2209pub struct WireStructsCursor<'a> {
2213 val: &'a [u8],
2214 field_names: Vec<&'a [u8]>,
2215 n: usize,
2216 kind: CursorKind<'a>,
2217}
2218
2219enum CursorKind<'a> {
2220 Variable { row_table_pos: usize, rows_start: usize },
2221 Fixed { field_kinds: &'a [u8], field_offsets: Vec<usize>, stride: usize, rows_start: usize, blob: &'a [u8] },
2222}
2223
2224impl<'a> WireStructsCursor<'a> {
2225 pub fn len(&self) -> usize {
2226 self.n
2227 }
2228 pub fn is_empty(&self) -> bool {
2229 self.n == 0
2230 }
2231 pub fn field_count(&self) -> usize {
2232 self.field_names.len()
2233 }
2234 pub fn field_index(&self, name: &str) -> Option<usize> {
2236 self.field_names.iter().position(|&n| n == name.as_bytes())
2237 }
2238
2239 fn cell_slice(&self, row: usize, fi: usize) -> Option<&'a [u8]> {
2241 if row >= self.n || fi >= self.field_names.len() {
2242 return None;
2243 }
2244 match &self.kind {
2245 CursorKind::Fixed { field_offsets, stride, rows_start, .. } => {
2246 let pos = rows_start.checked_add(row.checked_mul(*stride)?)?.checked_add(field_offsets[fi])?;
2247 self.val.get(pos..)
2248 }
2249 CursorKind::Variable { row_table_pos, rows_start } => {
2250 let f = self.field_names.len();
2251 let row_off_at = row_table_pos.checked_add(row.checked_mul(4)?)?;
2252 let row_off =
2253 u32::from_le_bytes(self.val.get(row_off_at..row_off_at.checked_add(4)?)?.try_into().ok()?) as usize;
2254 let field_table_pos = rows_start.checked_add(row_off)?;
2255 let values_start = field_table_pos.checked_add(f.checked_mul(4)?)?;
2256 let field_off_at = field_table_pos.checked_add(fi.checked_mul(4)?)?;
2257 let field_off =
2258 u32::from_le_bytes(self.val.get(field_off_at..field_off_at.checked_add(4)?)?.try_into().ok()?) as usize;
2259 self.val.get(values_start.checked_add(field_off)?..)
2260 }
2261 }
2262 }
2263
2264 pub fn value(&self, row: usize, fi: usize) -> Option<RuntimeValue> {
2266 match &self.kind {
2267 CursorKind::Fixed { field_kinds, blob, .. } => {
2268 fview_read_cell(*field_kinds.get(fi)?, self.cell_slice(row, fi)?, blob)
2269 }
2270 CursorKind::Variable { .. } => {
2271 let cell = self.cell_slice(row, fi)?;
2272 let mut q = 0;
2273 native_decode(cell, &mut q)
2274 }
2275 }
2276 }
2277
2278 pub fn i64_column(&self, fi: usize) -> Option<Vec<i64>> {
2284 let CursorKind::Fixed { field_kinds, field_offsets, stride, rows_start, .. } = &self.kind else {
2285 return None;
2286 };
2287 if *field_kinds.get(fi)? != FK_INT {
2288 return None;
2289 }
2290 let base = rows_start.checked_add(field_offsets[fi])?;
2291 let mut out = Vec::with_capacity(self.n);
2292 if self.n > 0 {
2293 let last = base.checked_add((self.n - 1).checked_mul(*stride)?)?;
2296 self.val.get(last..last.checked_add(8)?)?;
2297 let ptr = self.val.as_ptr();
2298 for r in 0..self.n {
2299 let p = base + r * stride;
2300 let b = unsafe { std::slice::from_raw_parts(ptr.add(p), 8) };
2302 out.push(i64::from_le_bytes(b.try_into().unwrap()));
2303 }
2304 }
2305 Some(out)
2306 }
2307
2308 pub fn i64(&self, row: usize, fi: usize) -> Option<i64> {
2312 let cell = self.cell_slice(row, fi)?;
2313 match &self.kind {
2314 CursorKind::Fixed { field_kinds, .. } => match *field_kinds.get(fi)? {
2315 FK_INT => Some(i64::from_le_bytes(cell.get(0..8)?.try_into().ok()?)),
2316 _ => None,
2317 },
2318 CursorKind::Variable { .. } => {
2319 if *cell.first()? != T_INT {
2320 return None;
2321 }
2322 let mut q = 1;
2323 Some(unzigzag(read_uvarint(cell, &mut q)?))
2324 }
2325 }
2326 }
2327}
2328
2329const T_NOTHING: u8 = 0;
2330const T_FALSE: u8 = 1;
2331const T_TRUE: u8 = 2;
2332const T_INT: u8 = 3;
2333const T_FLOAT: u8 = 4;
2334const T_CHAR: u8 = 5;
2335const T_TEXT: u8 = 6;
2336const T_DURATION: u8 = 7;
2337const T_DATE: u8 = 8;
2338const T_MOMENT: u8 = 9;
2339const T_SPAN: u8 = 10;
2340const T_TIME: u8 = 11;
2341const T_PEER: u8 = 12;
2342const T_LIST: u8 = 13;
2343const T_TUPLE: u8 = 14;
2344const T_SET: u8 = 15;
2345const T_MAP: u8 = 16;
2346const T_STRUCT: u8 = 17;
2347const T_INDUCTIVE: u8 = 18;
2348const T_INTS: u8 = 19; const T_FLOATS: u8 = 20; const T_BOOLS: u8 = 21; const T_STRINGS: u8 = 22; const T_INTS_FIXED: u8 = 23; const T_INTS_GV: u8 = 24; const T_STRUCTS: u8 = 25; const T_INDUCTIVES: u8 = 26; const T_STRUCTS_DEF: u8 = 27; const T_STRUCTS_REF: u8 = 28; const T_STRUCTS_CDEF: u8 = 29; const T_STRUCTS_CREF: u8 = 30; const T_FLOATS_XOR: u8 = 31; const T_INTS_AFFINE: u8 = 32; const T_BIGINT: u8 = 33; const T_RATIONAL: u8 = 34; const T_DECIMAL: u8 = 75; const T_COMPLEX: u8 = 76; const T_MODULAR: u8 = 77; const T_QUANTITY: u8 = 79; const T_MONEY: u8 = 80; const T_UUID: u8 = 81; const T_STRUCT_DEF: u8 = 35; const T_STRUCT_REF: u8 = 36; const T_STRUCT_CDEF: u8 = 37; const T_STRUCT_CREF: u8 = 38; const T_INTS_DELTA: u8 = 39; const T_INTS_DOD: u8 = 40; const T_INTS_FOR: u8 = 41; const T_INTS_RLE: u8 = 42; const T_INTS_DICT: u8 = 43; const T_INTS_POLY: u8 = 50; const T_GEN: u8 = 51; const T_FUNC: u8 = 52; const T_BYTES: u8 = 53; const T_STRUCTS_TID: u8 = 54; const T_SET_INTS: u8 = 55; const T_STRUCTS_FVIEW: u8 = 56; const T_SET_STRINGS: u8 = 57; const T_MAP_INTKEY: u8 = 58; const T_STRINGS_DICT: u8 = 59; const FK_INT: u8 = 0; const FK_FLOAT: u8 = 1; const FK_BOOL: u8 = 2; const FK_TEXT: u8 = 3; fn fview_width(kind: u8) -> usize {
2411 match kind {
2412 FK_BOOL => 1,
2413 _ => 8, }
2415}
2416
2417fn fview_layout(kinds: &[u8]) -> (Vec<usize>, usize) {
2419 let mut offsets = Vec::with_capacity(kinds.len());
2420 let mut cur = 0usize;
2421 for &k in kinds {
2422 offsets.push(cur);
2423 cur += fview_width(k);
2424 }
2425 (offsets, cur)
2426}
2427
2428fn columns_fview_kinds(columns: &[ListRepr]) -> Option<Vec<u8>> {
2431 let mut kinds = Vec::with_capacity(columns.len());
2432 for col in columns {
2433 kinds.push(match col {
2434 ListRepr::Ints(_) | ListRepr::IntsI32(_) => FK_INT,
2435 ListRepr::Floats(_) => FK_FLOAT,
2436 ListRepr::Bools(_) => FK_BOOL,
2437 ListRepr::Strings { .. } => FK_TEXT,
2438 _ => return None,
2439 });
2440 }
2441 Some(kinds)
2442}
2443
2444fn fview_read_cell(kind: u8, cell: &[u8], blob: &[u8]) -> Option<RuntimeValue> {
2446 match kind {
2447 FK_INT => Some(RuntimeValue::Int(i64::from_le_bytes(cell.get(0..8)?.try_into().ok()?))),
2448 FK_FLOAT => Some(RuntimeValue::Float(f64::from_le_bytes(cell.get(0..8)?.try_into().ok()?))),
2449 FK_BOOL => Some(RuntimeValue::Bool(*cell.first()? != 0)),
2450 FK_TEXT => {
2451 let off = u32::from_le_bytes(cell.get(0..4)?.try_into().ok()?) as usize;
2452 let len = u32::from_le_bytes(cell.get(4..8)?.try_into().ok()?) as usize;
2453 let s = blob.get(off..off.checked_add(len)?)?;
2454 Some(RuntimeValue::Text(Rc::new(String::from_utf8(s.to_vec()).ok()?)))
2455 }
2456 _ => None,
2457 }
2458}
2459const T_STRUCT_TID: u8 = 44; const T_WORD: u8 = 60; const T_INTS_GEOMETRIC: u8 = 61; const T_INTS_PERIODIC: u8 = 62; const T_SHARED_DEF: u8 = 63; const T_SHARED_REF: u8 = 64; const T_FLOATS_CONST: u8 = 65; const T_FLOATS_AFFINE: u8 = 66; const T_INTS_SPARSE: u8 = 67; const T_FLOATS_SPARSE: u8 = 68; const T_FLOATS_PERIODIC: u8 = 69; const T_FLOATS_GEOMETRIC: u8 = 70; const T_STRINGS_TEMPLATE: u8 = 71; const T_STRINGS_FRONT: u8 = 72; const T_BOOLS_PERIODIC: u8 = 73; const T_BOOLS_RLE: u8 = 74; const T_STRINGS_AFFIX: u8 = 78; const T_INDUCTIVE_TID: u8 = 45; const T_STRUCT_VIEW: u8 = 46; const T_INTS_ALIGNED: u8 = 47; const T_FLOATS_ALIGNED: u8 = 48; const T_STRUCTS_VIEW: u8 = 49; #[derive(Debug, Clone, Copy, PartialEq, Eq)]
2505pub enum WireNumerics {
2506 Varint,
2509 Fixed,
2512 GroupVarint,
2516}
2517
2518#[derive(Clone, Copy, PartialEq, Eq, Debug)]
2525pub enum WireFloats {
2526 Memcpy,
2527 XorDelta,
2528}
2529
2530#[derive(Clone, Copy, PartialEq, Eq, Debug)]
2537pub enum WireStructure {
2538 Off,
2540 Affine,
2545 Auto,
2553}
2554
2555thread_local! {
2556 static NUMERICS: std::cell::Cell<WireNumerics> = const { std::cell::Cell::new(WireNumerics::Varint) };
2557 static FLOATS: std::cell::Cell<WireFloats> = const { std::cell::Cell::new(WireFloats::Memcpy) };
2558 static STRUCTURE: std::cell::Cell<WireStructure> = const { std::cell::Cell::new(WireStructure::Off) };
2559 static FLAT_LISTS: std::cell::Cell<bool> = const { std::cell::Cell::new(false) };
2564}
2565
2566pub fn with_flat_lists<T>(on: bool, f: impl FnOnce() -> T) -> T {
2568 let prev = FLAT_LISTS.with(|c| c.replace(on));
2569 let out = f();
2570 FLAT_LISTS.with(|c| c.set(prev));
2571 out
2572}
2573
2574#[inline]
2575fn flat_lists() -> bool {
2576 FLAT_LISTS.with(|c| c.get())
2577}
2578
2579pub fn with_numerics<T>(n: WireNumerics, f: impl FnOnce() -> T) -> T {
2581 let prev = NUMERICS.with(|c| c.replace(n));
2582 let out = f();
2583 NUMERICS.with(|c| c.set(prev));
2584 out
2585}
2586
2587pub fn with_fixed_numerics<T>(f: impl FnOnce() -> T) -> T {
2589 with_numerics(WireNumerics::Fixed, f)
2590}
2591
2592fn numerics() -> WireNumerics {
2593 NUMERICS.with(std::cell::Cell::get)
2594}
2595
2596pub fn with_structure<T>(s: WireStructure, f: impl FnOnce() -> T) -> T {
2599 let prev = STRUCTURE.with(|c| c.replace(s));
2600 let out = f();
2601 STRUCTURE.with(|c| c.set(prev));
2602 out
2603}
2604
2605fn structure() -> WireStructure {
2606 STRUCTURE.with(std::cell::Cell::get)
2607}
2608
2609const PERIOD_CAP: usize = 512;
2612
2613pub(crate) fn lower_expr_to_genexpr(e: &crate::ast::stmt::Expr<'_>, param: logicaffeine_base::Symbol) -> Option<GenExpr> {
2619 use crate::ast::stmt::{BinaryOpKind, Expr, Literal};
2620 match e {
2621 Expr::Literal(Literal::Number(n)) => Some(GenExpr::Const(*n)),
2622 Expr::Identifier(s) if *s == param => Some(GenExpr::Index),
2623 Expr::BinaryOp { op, left, right } => {
2624 let l = Box::new(lower_expr_to_genexpr(left, param)?);
2625 let r = Box::new(lower_expr_to_genexpr(right, param)?);
2626 Some(match op {
2627 BinaryOpKind::Add => GenExpr::Add(l, r),
2628 BinaryOpKind::Subtract => GenExpr::Sub(l, r),
2629 BinaryOpKind::Multiply => GenExpr::Mul(l, r),
2630 BinaryOpKind::Divide => GenExpr::Div(l, r),
2631 BinaryOpKind::Modulo => GenExpr::Mod(l, r),
2632 _ => return None,
2633 })
2634 }
2635 _ => None,
2636 }
2637}
2638
2639fn bitpack(vals: &[u64], width: u8) -> Vec<u8> {
2641 if width == 0 {
2642 return Vec::new();
2643 }
2644 let total_bits = vals.len().saturating_mul(width as usize);
2645 let mut out = vec![0u8; total_bits.div_ceil(8)];
2646 let mut bitpos = 0usize;
2647 for &val in vals {
2648 let mut bits = val;
2649 let mut remaining = width as usize;
2650 while remaining > 0 {
2651 let byte = bitpos / 8;
2652 let off = bitpos % 8;
2653 let take = remaining.min(8 - off);
2654 let mask = (1u64 << take) - 1;
2655 out[byte] |= ((bits & mask) as u8) << off;
2656 bits >>= take;
2657 bitpos += take;
2658 remaining -= take;
2659 }
2660 }
2661 out
2662}
2663
2664fn bitunpack(bytes: &[u8], count: usize, width: u8) -> Option<Vec<u64>> {
2667 if width == 0 || width > 64 {
2668 return None;
2669 }
2670 let total_bits = count.checked_mul(width as usize)?;
2671 if bytes.len() < total_bits.div_ceil(8) {
2672 return None;
2673 }
2674 let mut out = Vec::with_capacity(count.min(PREALLOC_CAP));
2675 let mut bitpos = 0usize;
2676 for _ in 0..count {
2677 let mut val = 0u64;
2678 let mut got = 0usize;
2679 while got < width as usize {
2680 let byte = bitpos / 8;
2681 let off = bitpos % 8;
2682 let take = (width as usize - got).min(8 - off);
2683 let mask = (1u64 << take) - 1;
2684 val |= (((bytes[byte] >> off) as u64) & mask) << got;
2685 got += take;
2686 bitpos += take;
2687 }
2688 out.push(val);
2689 }
2690 Some(out)
2691}
2692
2693pub fn with_floats<T>(mode: WireFloats, f: impl FnOnce() -> T) -> T {
2695 let prev = FLOATS.with(|c| c.replace(mode));
2696 let out = f();
2697 FLOATS.with(|c| c.set(prev));
2698 out
2699}
2700
2701fn floats_mode() -> WireFloats {
2702 FLOATS.with(std::cell::Cell::get)
2703}
2704
2705fn detect_float_const(v: &[f64]) -> Option<u64> {
2709 let bits = v.first()?.to_bits();
2710 v.iter().all(|x| x.to_bits() == bits).then_some(bits)
2711}
2712
2713fn detect_float_affine(v: &[f64]) -> Option<(f64, f64)> {
2719 if v.len() < 3 {
2720 return None;
2721 }
2722 let base = v[0];
2723 let stride = v[1] - v[0];
2724 for (i, &x) in v.iter().enumerate() {
2725 if (base + (i as f64) * stride).to_bits() != x.to_bits() {
2726 return None;
2727 }
2728 }
2729 Some((base, stride))
2730}
2731
2732fn detect_float_sparse(v: &[f64]) -> Option<(u64, Vec<(usize, u64)>)> {
2737 if v.len() < 8 {
2738 return None;
2739 }
2740 let mut cand = v[0].to_bits();
2741 let mut count: i64 = 0;
2742 for x in v {
2743 let b = x.to_bits();
2744 if count == 0 {
2745 cand = b;
2746 count = 1;
2747 } else if b == cand {
2748 count += 1;
2749 } else {
2750 count -= 1;
2751 }
2752 }
2753 let occ = v.iter().filter(|x| x.to_bits() == cand).count();
2754 if v.len() - occ > v.len() / 4 {
2755 return None;
2756 }
2757 let exceptions: Vec<(usize, u64)> = v
2758 .iter()
2759 .enumerate()
2760 .filter(|(_, x)| x.to_bits() != cand)
2761 .map(|(i, x)| (i, x.to_bits()))
2762 .collect();
2763 Some((cand, exceptions))
2764}
2765
2766fn detect_float_period(v: &[f64]) -> Option<usize> {
2770 let n = v.len();
2771 if n < 4 {
2772 return None;
2773 }
2774 let cap = (n / 2).min(PERIOD_CAP);
2775 'p: for p in 2..=cap {
2776 for i in p..n {
2777 if v[i].to_bits() != v[i - p].to_bits() {
2778 continue 'p;
2779 }
2780 }
2781 return Some(p);
2782 }
2783 None
2784}
2785
2786fn detect_float_geometric(v: &[f64]) -> Option<(f64, f64)> {
2791 if v.len() < 3 {
2792 return None;
2793 }
2794 let base = v[0];
2795 if base == 0.0 || !base.is_finite() {
2796 return None;
2797 }
2798 let ratio = v[1] / base;
2799 if !ratio.is_finite() || ratio == 1.0 {
2800 return None; }
2802 let mut cur = base;
2803 for &x in v {
2804 if cur.to_bits() != x.to_bits() {
2805 return None;
2806 }
2807 cur *= ratio;
2808 }
2809 Some((base, ratio))
2810}
2811
2812fn floats_xor_encode(out: &mut Vec<u8>, v: &[f64]) {
2815 write_uvarint(v.len() as u64, out);
2816 let mut prev = 0u64;
2817 for &f in v {
2818 let bits = f.to_bits();
2819 write_uvarint(bits ^ prev, out);
2820 prev = bits;
2821 }
2822}
2823
2824fn uvarint_byte_len(x: u64) -> usize {
2826 (((64 - x.leading_zeros()).max(1) + 6) / 7) as usize
2827}
2828
2829fn floats_memcpy_body_len(n: usize) -> usize {
2832 uvarint_byte_len(n as u64) + n * 8
2833}
2834
2835#[derive(Clone, Copy, PartialEq, Eq, Debug)]
2840pub enum WireCompression {
2841 None,
2844 Deflate,
2846 Lz4,
2849 Zstd,
2852}
2853
2854fn compression_id(c: WireCompression) -> u8 {
2857 match c {
2858 WireCompression::None | WireCompression::Deflate => 0,
2859 WireCompression::Lz4 => 1,
2860 WireCompression::Zstd => 2,
2861 }
2862}
2863
2864#[derive(Clone, Copy, PartialEq, Eq, Debug)]
2868pub enum WireCompressionLevel {
2869 Fast,
2870 Balanced,
2871 Max,
2872}
2873
2874thread_local! {
2875 static COMPRESSION_CODEC: std::cell::Cell<WireCompression> =
2876 const { std::cell::Cell::new(WireCompression::None) };
2877 static COMPRESSION_LEVEL: std::cell::Cell<WireCompressionLevel> =
2878 const { std::cell::Cell::new(WireCompressionLevel::Balanced) };
2879}
2880
2881pub fn with_compression_codec<T>(codec: WireCompression, f: impl FnOnce() -> T) -> T {
2884 let prev = COMPRESSION_CODEC.with(|c| c.replace(codec));
2885 let out = f();
2886 COMPRESSION_CODEC.with(|c| c.set(prev));
2887 out
2888}
2889
2890pub fn with_compression_level<T>(level: WireCompressionLevel, f: impl FnOnce() -> T) -> T {
2892 let prev = COMPRESSION_LEVEL.with(|c| c.replace(level));
2893 let out = f();
2894 COMPRESSION_LEVEL.with(|c| c.set(prev));
2895 out
2896}
2897
2898fn compression_level() -> WireCompressionLevel {
2899 COMPRESSION_LEVEL.with(std::cell::Cell::get)
2900}
2901
2902fn deflate_level() -> u8 {
2904 match compression_level() {
2905 WireCompressionLevel::Fast => 1,
2906 WireCompressionLevel::Balanced => 6,
2907 WireCompressionLevel::Max => 9,
2908 }
2909}
2910
2911#[cfg(not(target_arch = "wasm32"))]
2914fn zstd_level() -> i32 {
2915 match compression_level() {
2916 WireCompressionLevel::Fast => 1,
2917 WireCompressionLevel::Balanced => 9,
2918 WireCompressionLevel::Max => 19,
2919 }
2920}
2921
2922pub fn with_compression<T>(f: impl FnOnce() -> T) -> T {
2925 with_compression_codec(WireCompression::Deflate, f)
2926}
2927
2928fn compression_codec() -> WireCompression {
2929 COMPRESSION_CODEC.with(std::cell::Cell::get)
2930}
2931
2932fn compress_body(codec: WireCompression, body: &[u8]) -> Option<(WireCompression, Vec<u8>)> {
2936 match codec {
2937 WireCompression::None => None,
2938 WireCompression::Deflate => Some((codec, miniz_oxide::deflate::compress_to_vec(body, deflate_level()))),
2939 WireCompression::Lz4 => Some((codec, lz4_flex::compress_prepend_size(body))),
2940 WireCompression::Zstd => {
2941 #[cfg(not(target_arch = "wasm32"))]
2942 {
2943 zstd::encode_all(body, zstd_level()).ok().map(|z| (WireCompression::Zstd, z))
2944 }
2945 #[cfg(target_arch = "wasm32")]
2946 {
2947 Some((WireCompression::Lz4, lz4_flex::compress_prepend_size(body)))
2950 }
2951 }
2952 }
2953}
2954
2955pub fn best_compressed_len(body: &[u8]) -> usize {
2961 [WireCompression::Deflate, WireCompression::Lz4, WireCompression::Zstd]
2962 .into_iter()
2963 .filter_map(|c| compress_body(c, body).map(|(_, z)| z.len()))
2964 .fold(body.len(), usize::min)
2965}
2966
2967fn decompress_body(codec: WireCompression, body: &[u8]) -> Option<Vec<u8>> {
2969 match codec {
2970 WireCompression::None => Some(body.to_vec()),
2971 WireCompression::Deflate => miniz_oxide::inflate::decompress_to_vec(body).ok(),
2972 WireCompression::Lz4 => lz4_flex::decompress_size_prepended(body).ok(),
2973 WireCompression::Zstd => {
2974 #[cfg(not(target_arch = "wasm32"))]
2975 {
2976 zstd::decode_all(body).ok()
2977 }
2978 #[cfg(target_arch = "wasm32")]
2979 {
2980 zstd_decode_ruzstd(body)
2981 }
2982 }
2983 }
2984}
2985
2986fn zstd_decode_ruzstd(body: &[u8]) -> Option<Vec<u8>> {
2989 use std::io::Read;
2990 let mut dec = ruzstd::StreamingDecoder::new(body).ok()?;
2991 let mut out = Vec::new();
2992 dec.read_to_end(&mut out).ok()?;
2993 Some(out)
2994}
2995
2996#[inline]
3005fn gv_code(zz: u64) -> u8 {
3006 if zz <= 0xFF {
3007 0
3008 } else if zz <= 0xFFFF {
3009 1
3010 } else if zz <= 0xFFFF_FFFF {
3011 2
3012 } else {
3013 3
3014 }
3015}
3016
3017fn leb128_encode<I: Iterator<Item = i64> + Clone>(out: &mut Vec<u8>, vals: I, n: usize) {
3028 let signed = vals.clone().any(|x| x < 0);
3029 write_uvarint(((n as u64) << 1) | signed as u64, out);
3030 out.reserve(n * 2);
3031 if signed {
3032 for x in vals {
3033 write_uvarint(zigzag(x), out);
3034 }
3035 } else {
3036 for x in vals {
3037 write_uvarint(x as u64, out);
3038 }
3039 }
3040}
3041
3042fn fixed_encode_i64(out: &mut Vec<u8>, v: &[i64]) {
3045 write_uvarint(v.len() as u64, out);
3046 #[cfg(target_endian = "little")]
3047 {
3048 let bytes = unsafe { std::slice::from_raw_parts(v.as_ptr().cast::<u8>(), std::mem::size_of_val(v)) };
3050 out.extend_from_slice(bytes);
3051 }
3052 #[cfg(target_endian = "big")]
3053 {
3054 out.reserve(v.len() * 8);
3055 for &n in v {
3056 out.extend_from_slice(&n.to_le_bytes());
3057 }
3058 }
3059}
3060
3061fn gv_encode<I: Iterator<Item = i64> + Clone>(out: &mut Vec<u8>, vals: I, n: usize) {
3062 write_uvarint(n as u64, out);
3063 let control_at = out.len();
3064 out.resize(control_at + n.div_ceil(4), 0);
3065 out.reserve(n * 2);
3066 for (i, x) in vals.enumerate() {
3067 let zz = zigzag(x);
3068 let code = gv_code(zz);
3069 out[control_at + (i >> 2)] |= code << ((i & 3) * 2);
3070 out.extend_from_slice(&zz.to_le_bytes()[..1usize << code]);
3071 }
3072}
3073
3074fn gv_decode(buf: &[u8], pos: &mut usize) -> Option<Vec<i64>> {
3075 let n = read_uvarint(buf, pos)? as usize;
3076 let control_len = n.div_ceil(4);
3077 let control = buf.get(*pos..pos.checked_add(control_len)?)?;
3078 let mut dpos = *pos + control_len;
3079 let len = buf.len();
3080 let mut v = Vec::with_capacity(n.min(PREALLOC_CAP));
3081 for i in 0..n {
3082 let code = (control[i >> 2] >> ((i & 3) * 2)) & 0x3;
3083 let width = 1usize << code;
3084 let zz = if dpos + 8 <= len {
3085 let word = u64::from_le_bytes(buf[dpos..dpos + 8].try_into().unwrap());
3088 let mask = if width == 8 { u64::MAX } else { (1u64 << (width * 8)) - 1 };
3089 word & mask
3090 } else {
3091 let raw = buf.get(dpos..dpos.checked_add(width)?)?;
3093 let mut b = [0u8; 8];
3094 b[..width].copy_from_slice(raw);
3095 u64::from_le_bytes(b)
3096 };
3097 dpos += width;
3098 v.push(unzigzag(zz));
3099 }
3100 *pos = dpos;
3101 Some(v)
3102}
3103
3104fn gv_decode_dispatch(buf: &[u8], pos: &mut usize) -> Option<Vec<i64>> {
3108 #[cfg(target_arch = "x86_64")]
3109 {
3110 if is_x86_feature_detected!("ssse3") {
3111 return unsafe { gv_decode_ssse3(buf, pos) };
3113 }
3114 }
3115 gv_decode(buf, pos)
3116}
3117
3118#[cfg(target_arch = "x86_64")]
3123fn gv_shuffle_masks() -> &'static [[u8; 16]; 16] {
3124 use std::sync::OnceLock;
3125 static MASKS: OnceLock<[[u8; 16]; 16]> = OnceLock::new();
3126 MASKS.get_or_init(|| {
3127 let mut m = [[0x80u8; 16]; 16];
3128 for ca in 0..4usize {
3129 for cb in 0..4usize {
3130 let (wa, wb) = (1usize << ca, 1usize << cb);
3131 let entry = &mut m[(ca << 2) | cb];
3132 for j in 0..wa {
3133 entry[j] = j as u8;
3134 }
3135 for k in 0..wb {
3136 entry[8 + k] = (wa + k) as u8;
3137 }
3138 }
3139 }
3140 m
3141 })
3142}
3143
3144#[cfg(target_arch = "x86_64")]
3150#[target_feature(enable = "ssse3")]
3151unsafe fn gv_decode_ssse3(buf: &[u8], pos: &mut usize) -> Option<Vec<i64>> {
3152 use std::arch::x86_64::*;
3153 let n = read_uvarint(buf, pos)? as usize;
3154 let control_len = n.div_ceil(4);
3155 let control = buf.get(*pos..pos.checked_add(control_len)?)?;
3156 let mut dpos = *pos + control_len;
3157 let len = buf.len();
3158 let mut v = Vec::with_capacity(n.min(PREALLOC_CAP));
3159 let masks = gv_shuffle_masks();
3160 let mut i = 0;
3161 while i + 2 <= n && dpos + 16 <= len {
3162 let ctrl = control[i >> 2];
3163 let ca = ((ctrl >> ((i & 3) * 2)) & 0x3) as usize;
3164 let cb = ((ctrl >> (((i + 1) & 3) * 2)) & 0x3) as usize;
3165 let data = _mm_loadu_si128(buf.as_ptr().add(dpos).cast());
3166 let mask = _mm_loadu_si128(masks[(ca << 2) | cb].as_ptr().cast());
3167 let out = _mm_shuffle_epi8(data, mask);
3168 let mut tmp = [0u8; 16];
3169 _mm_storeu_si128(tmp.as_mut_ptr().cast(), out);
3170 v.push(unzigzag(u64::from_le_bytes(tmp[0..8].try_into().unwrap())));
3171 v.push(unzigzag(u64::from_le_bytes(tmp[8..16].try_into().unwrap())));
3172 dpos += (1usize << ca) + (1usize << cb);
3173 i += 2;
3174 }
3175 while i < n {
3176 let code = (control[i >> 2] >> ((i & 3) * 2)) & 0x3;
3177 let width = 1usize << code;
3178 let raw = buf.get(dpos..dpos.checked_add(width)?)?;
3179 let mut b = [0u8; 8];
3180 b[..width].copy_from_slice(raw);
3181 v.push(unzigzag(u64::from_le_bytes(b)));
3182 dpos += width;
3183 i += 1;
3184 }
3185 *pos = dpos;
3186 Some(v)
3187}
3188
3189#[inline]
3190fn write_uvarint(mut x: u64, out: &mut Vec<u8>) {
3191 while x >= 0x80 {
3192 out.push((x as u8) | 0x80);
3193 x >>= 7;
3194 }
3195 out.push(x as u8);
3196}
3197
3198#[inline]
3199fn read_uvarint(buf: &[u8], pos: &mut usize) -> Option<u64> {
3200 let mut result = 0u64;
3201 let mut shift = 0u32;
3202 loop {
3203 let b = *buf.get(*pos)?;
3204 *pos += 1;
3205 if shift >= 64 {
3206 return None; }
3208 result |= u64::from(b & 0x7f) << shift;
3209 if b & 0x80 == 0 {
3210 return Some(result);
3211 }
3212 shift += 7;
3213 }
3214}
3215
3216#[inline]
3217fn zigzag(x: i64) -> u64 {
3218 ((x << 1) ^ (x >> 63)) as u64
3219}
3220
3221#[inline]
3222fn unzigzag(x: u64) -> i64 {
3223 ((x >> 1) as i64) ^ -((x & 1) as i64)
3224}
3225
3226#[inline]
3227fn write_str(s: &str, out: &mut Vec<u8>) {
3228 write_uvarint(s.len() as u64, out);
3229 out.extend_from_slice(s.as_bytes());
3230}
3231
3232#[inline]
3233fn read_str(buf: &[u8], pos: &mut usize) -> Option<String> {
3234 let n = read_uvarint(buf, pos)? as usize;
3235 let bytes = buf.get(*pos..pos.checked_add(n)?)?;
3236 *pos += n;
3237 String::from_utf8(bytes.to_vec()).ok()
3238}
3239
3240fn dict_encode_strings(data: &[u8], ends: &[u32]) -> Vec<u8> {
3247 let n = ends.len();
3248 let mut dict: Vec<&[u8]> = Vec::new();
3249 let mut index_of: std::collections::HashMap<&[u8], u64> = std::collections::HashMap::new();
3250 let mut indices: Vec<u64> = Vec::with_capacity(n);
3251 let mut prev = 0u32;
3252 for &e in ends {
3253 let s = &data[prev as usize..e as usize];
3254 prev = e;
3255 let idx = *index_of.entry(s).or_insert_with(|| {
3256 dict.push(s);
3257 (dict.len() - 1) as u64
3258 });
3259 indices.push(idx);
3260 }
3261 let mut out = vec![T_STRINGS_DICT];
3262 write_uvarint(dict.len() as u64, &mut out);
3263 for d in &dict {
3264 write_uvarint(d.len() as u64, &mut out);
3265 out.extend_from_slice(d);
3266 }
3267 write_uvarint(n as u64, &mut out);
3268 let iw = if dict.len() <= 1 { 0 } else { (64 - ((dict.len() - 1) as u64).leading_zeros()) as u8 };
3269 out.push(iw);
3270 if iw > 0 {
3271 out.extend_from_slice(&bitpack(&indices, iw));
3272 }
3273 out
3274}
3275
3276fn string_slices<'a>(data: &'a [u8], ends: &[u32]) -> Vec<&'a [u8]> {
3280 let mut out = Vec::with_capacity(ends.len());
3281 let mut prev = 0usize;
3282 for &e in ends {
3283 out.push(&data[prev..e as usize]);
3284 prev = e as usize;
3285 }
3286 out
3287}
3288
3289fn try_template_encode(data: &[u8], ends: &[u32]) -> Option<Vec<u8>> {
3295 let n = ends.len();
3296 if n < 3 {
3297 return None;
3298 }
3299 let strs = string_slices(data, ends);
3300 let first = strs[0];
3301 let mut prefix_len = first.len();
3303 for s in &strs[1..] {
3304 let lim = prefix_len.min(s.len());
3305 let mut i = 0;
3306 while i < lim && first[i] == s[i] {
3307 i += 1;
3308 }
3309 prefix_len = i;
3310 }
3311 let mut suffix_len = first.len() - prefix_len;
3313 for s in &strs[1..] {
3314 let lim = suffix_len.min(s.len() - prefix_len);
3315 let mut i = 0;
3316 while i < lim && first[first.len() - 1 - i] == s[s.len() - 1 - i] {
3317 i += 1;
3318 }
3319 suffix_len = i;
3320 }
3321 let mut nums = Vec::with_capacity(n);
3323 for s in &strs {
3324 let mid = &s[prefix_len..s.len() - suffix_len];
3325 let mid_str = std::str::from_utf8(mid).ok()?;
3326 let num: i64 = mid_str.parse().ok()?;
3327 if num.to_string().as_bytes() != mid {
3328 return None;
3329 }
3330 nums.push(num);
3331 }
3332 let (base, stride) = detect_affine(&nums)?;
3333 let mut c = vec![T_STRINGS_TEMPLATE];
3334 write_uvarint(prefix_len as u64, &mut c);
3335 c.extend_from_slice(&first[..prefix_len]);
3336 write_uvarint(suffix_len as u64, &mut c);
3337 c.extend_from_slice(&first[first.len() - suffix_len..]);
3338 write_uvarint(zigzag(base), &mut c);
3339 write_uvarint(zigzag(stride), &mut c);
3340 write_uvarint(n as u64, &mut c);
3341 Some(c)
3342}
3343
3344fn front_code_strings(data: &[u8], ends: &[u32]) -> Vec<u8> {
3352 let strs = string_slices(data, ends);
3353 let mut out = vec![T_STRINGS_FRONT];
3354 write_uvarint(strs.len() as u64, &mut out);
3355 let mut prev: &[u8] = &[];
3356 for s in &strs {
3357 let lim = prev.len().min(s.len());
3358 let mut common = 0usize;
3359 while common < lim && prev[common] == s[common] {
3360 common += 1;
3361 }
3362 while common > 0 && common < s.len() && (s[common] & 0xC0) == 0x80 {
3364 common -= 1;
3365 }
3366 write_uvarint(common as u64, &mut out);
3367 write_uvarint((s.len() - common) as u64, &mut out);
3368 out.extend_from_slice(&s[common..]);
3369 prev = s;
3370 }
3371 out
3372}
3373
3374fn bool_bitpack(v: &[bool], out: &mut Vec<u8>) {
3376 out.push(T_BOOLS);
3377 write_uvarint(v.len() as u64, out);
3378 let mut cur = 0u8;
3379 let mut nbits = 0u8;
3380 for &b in v {
3381 cur |= u8::from(b) << nbits;
3382 nbits += 1;
3383 if nbits == 8 {
3384 out.push(cur);
3385 cur = 0;
3386 nbits = 0;
3387 }
3388 }
3389 if nbits > 0 {
3390 out.push(cur);
3391 }
3392}
3393
3394const BOOL_PERIOD_CAP: usize = 256;
3397
3398fn detect_bool_period(v: &[bool]) -> Option<usize> {
3401 let n = v.len();
3402 let cap = (n / 2).min(BOOL_PERIOD_CAP);
3403 'p: for p in 1..=cap {
3404 for i in p..n {
3405 if v[i] != v[i - p] {
3406 continue 'p;
3407 }
3408 }
3409 return Some(p);
3410 }
3411 None
3412}
3413
3414fn bool_periodic_encode(v: &[bool], p: usize) -> Vec<u8> {
3416 let mut c = vec![T_BOOLS_PERIODIC];
3417 write_uvarint(p as u64, &mut c);
3418 write_uvarint(v.len() as u64, &mut c);
3419 let mut cur = 0u8;
3420 let mut nbits = 0u8;
3421 for &b in &v[..p] {
3422 cur |= u8::from(b) << nbits;
3423 nbits += 1;
3424 if nbits == 8 {
3425 c.push(cur);
3426 cur = 0;
3427 nbits = 0;
3428 }
3429 }
3430 if nbits > 0 {
3431 c.push(cur);
3432 }
3433 c
3434}
3435
3436fn bool_rle_encode(v: &[bool]) -> Vec<u8> {
3440 let mut c = vec![T_BOOLS_RLE];
3441 write_uvarint(v.len() as u64, &mut c);
3442 if v.is_empty() {
3443 c.push(0); write_uvarint(0, &mut c);
3445 return c;
3446 }
3447 c.push(v[0] as u8);
3448 let mut runs: Vec<u64> = Vec::new();
3449 let mut cur = v[0];
3450 let mut len = 0u64;
3451 for &b in v {
3452 if b == cur {
3453 len += 1;
3454 } else {
3455 runs.push(len);
3456 cur = b;
3457 len = 1;
3458 }
3459 }
3460 runs.push(len);
3461 write_uvarint(runs.len() as u64, &mut c);
3462 for r in runs {
3463 write_uvarint(r, &mut c);
3464 }
3465 c
3466}
3467
3468fn emit_best_bool_column(v: &[bool], out: &mut Vec<u8>) {
3469 let mut best = Vec::new();
3470 bool_bitpack(v, &mut best);
3471 if let Some(p) = detect_bool_period(v) {
3472 consider(&mut best, bool_periodic_encode(v, p));
3473 }
3474 consider(&mut best, bool_rle_encode(v));
3475 out.extend_from_slice(&best);
3476}
3477
3478fn common_affix_lens(strs: &[&[u8]]) -> (usize, usize) {
3482 let first = strs[0];
3483 let mut prefix_len = first.len();
3484 for s in &strs[1..] {
3485 let lim = prefix_len.min(s.len());
3486 let mut i = 0;
3487 while i < lim && first[i] == s[i] {
3488 i += 1;
3489 }
3490 prefix_len = i;
3491 }
3492 while prefix_len > 0 && prefix_len < first.len() && (first[prefix_len] & 0xC0) == 0x80 {
3493 prefix_len -= 1;
3494 }
3495 let mut suffix_len = first.len() - prefix_len;
3496 for s in &strs[1..] {
3497 let lim = suffix_len.min(s.len() - prefix_len);
3498 let mut i = 0;
3499 while i < lim && first[first.len() - 1 - i] == s[s.len() - 1 - i] {
3500 i += 1;
3501 }
3502 suffix_len = i;
3503 }
3504 while suffix_len > 0 && (first[first.len() - suffix_len] & 0xC0) == 0x80 {
3505 suffix_len -= 1;
3506 }
3507 (prefix_len, suffix_len)
3508}
3509
3510fn try_affix_encode(data: &[u8], ends: &[u32]) -> Option<Vec<u8>> {
3516 let n = ends.len();
3517 if n < 2 {
3518 return None;
3519 }
3520 let strs = string_slices(data, ends);
3521 let (prefix_len, suffix_len) = common_affix_lens(&strs);
3522 if prefix_len + suffix_len == 0 {
3523 return None;
3524 }
3525 let first = strs[0];
3526 let mut c = vec![T_STRINGS_AFFIX];
3527 write_uvarint(prefix_len as u64, &mut c);
3528 c.extend_from_slice(&first[..prefix_len]);
3529 write_uvarint(suffix_len as u64, &mut c);
3530 c.extend_from_slice(&first[first.len() - suffix_len..]);
3531 write_uvarint(n as u64, &mut c);
3532 for s in &strs {
3533 let mid = &s[prefix_len..s.len() - suffix_len];
3534 write_uvarint(mid.len() as u64, &mut c);
3535 c.extend_from_slice(mid);
3536 }
3537 Some(c)
3538}
3539
3540fn emit_best_string_column(data: &[u8], ends: &[u32], out: &mut Vec<u8>) {
3541 let mut best = Vec::new();
3542 write_string_array_from_ends(&mut best, data, ends);
3543 consider(&mut best, dict_encode_strings(data, ends));
3544 consider(&mut best, front_code_strings(data, ends));
3545 if let Some(tpl) = try_template_encode(data, ends) {
3546 consider(&mut best, tpl);
3547 }
3548 if let Some(affix) = try_affix_encode(data, ends) {
3549 consider(&mut best, affix);
3550 }
3551 out.extend_from_slice(&best);
3552}
3553
3554fn write_string_array_from_ends(out: &mut Vec<u8>, data: &[u8], ends: &[u32]) {
3555 out.push(T_STRINGS);
3556 write_uvarint(ends.len() as u64, out);
3557 let mut prev = 0u32;
3558 for &e in ends {
3559 write_uvarint(u64::from(e - prev), out);
3560 prev = e;
3561 }
3562 out.extend_from_slice(data);
3563}
3564
3565fn struct_schema(v: &[RuntimeValue]) -> Option<(String, Vec<String>)> {
3571 let first = match v.first()? {
3572 RuntimeValue::Struct(s) => s,
3573 _ => return None,
3574 };
3575 let mut names: Vec<String> = first.fields.keys().cloned().collect();
3576 names.sort();
3577 if names.is_empty() {
3580 return None;
3581 }
3582 for item in v {
3583 match item {
3584 RuntimeValue::Struct(s)
3585 if s.type_name == first.type_name
3586 && s.fields.len() == names.len()
3587 && names.iter().all(|n| s.fields.contains_key(n)) => {}
3588 _ => return None,
3589 }
3590 }
3591 Some((first.type_name.clone(), names))
3592}
3593
3594fn write_struct_schema(type_name: &str, field_names: &[String], out: &mut Vec<u8>) {
3604 write_str(type_name, out);
3605 write_uvarint(field_names.len() as u64, out);
3606 for f in field_names {
3607 write_str(f, out);
3608 }
3609}
3610
3611fn emit_struct_list(
3612 type_name: &str,
3613 field_names: &[String],
3614 n: usize,
3615 out: &mut Vec<u8>,
3616 encode_columns: impl FnOnce(&mut Vec<u8>) -> Result<(), String>,
3617) -> Result<(), String> {
3618 let write_schema = |out: &mut Vec<u8>| write_struct_schema(type_name, field_names, out);
3619 if let Some(id) = type_registry_id(type_name, field_names) {
3620 out.push(T_STRUCTS_TID);
3625 write_uvarint(id as u64, out);
3626 write_uvarint(n as u64, out);
3627 return encode_columns(out);
3628 }
3629 match schema_send(type_name, field_names) {
3630 SchemaEmit::Inline => {
3631 out.push(T_STRUCTS);
3632 write_schema(out);
3633 }
3634 SchemaEmit::SeqDef(id) => {
3635 out.push(T_STRUCTS_DEF);
3636 write_uvarint(id as u64, out);
3637 write_schema(out);
3638 }
3639 SchemaEmit::SeqRef(id) => {
3640 out.push(T_STRUCTS_REF);
3641 write_uvarint(id as u64, out);
3642 }
3643 SchemaEmit::CaDef => {
3644 out.push(T_STRUCTS_CDEF);
3645 write_schema(out);
3646 }
3647 SchemaEmit::CaRef(fp) => {
3648 out.push(T_STRUCTS_CREF);
3649 out.extend_from_slice(&fp.to_le_bytes());
3650 }
3651 }
3652 write_uvarint(n as u64, out);
3653 encode_columns(out)
3654}
3655
3656fn emit_structs_view(
3665 type_name: &str,
3666 field_names: &[String],
3667 n: usize,
3668 out: &mut Vec<u8>,
3669 mut get: impl FnMut(usize, usize) -> RuntimeValue,
3670) -> Result<(), String> {
3671 let f = field_names.len();
3672 out.push(T_STRUCTS_VIEW);
3673 write_str(type_name, out);
3674 write_uvarint(f as u64, out);
3675 for name in field_names {
3676 write_str(name, out);
3677 }
3678 write_uvarint(n as u64, out);
3679 let row_table_pos = out.len();
3680 out.resize(row_table_pos + n * 4, 0);
3681 let rows_start = out.len();
3682 let mut row_offsets: Vec<u32> = Vec::with_capacity(n);
3683 for r in 0..n {
3684 row_offsets.push((out.len() - rows_start) as u32);
3685 let field_table_pos = out.len();
3686 out.resize(field_table_pos + f * 4, 0);
3687 let values_start = out.len();
3688 let mut field_offsets: Vec<u32> = Vec::with_capacity(f);
3689 for fi in 0..f {
3690 field_offsets.push((out.len() - values_start) as u32);
3691 native_encode(&get(r, fi), out)?;
3692 }
3693 for (i, off) in field_offsets.iter().enumerate() {
3694 out[field_table_pos + i * 4..field_table_pos + i * 4 + 4].copy_from_slice(&off.to_le_bytes());
3695 }
3696 }
3697 for (i, off) in row_offsets.iter().enumerate() {
3698 out[row_table_pos + i * 4..row_table_pos + i * 4 + 4].copy_from_slice(&off.to_le_bytes());
3699 }
3700 Ok(())
3701}
3702
3703fn emit_structs_view_columnar(
3708 type_name: &str,
3709 field_names: &[String],
3710 columns: &[ListRepr],
3711 out: &mut Vec<u8>,
3712) -> Result<(), String> {
3713 let f = field_names.len();
3714 let n = columns.first().map_or(0, |c| c.len());
3715 out.push(T_STRUCTS_VIEW);
3716 write_str(type_name, out);
3717 write_uvarint(f as u64, out);
3718 for name in field_names {
3719 write_str(name, out);
3720 }
3721 write_uvarint(n as u64, out);
3722 let row_table_pos = out.len();
3723 out.resize(row_table_pos + n * 4, 0);
3724 let rows_start = out.len();
3725 let mut row_offsets: Vec<u32> = Vec::with_capacity(n);
3726 let mut field_offsets: Vec<u32> = Vec::with_capacity(f);
3727 for r in 0..n {
3728 row_offsets.push((out.len() - rows_start) as u32);
3729 let field_table_pos = out.len();
3730 out.resize(field_table_pos + f * 4, 0);
3731 let values_start = out.len();
3732 field_offsets.clear();
3733 for col in columns {
3734 field_offsets.push((out.len() - values_start) as u32);
3735 write_view_cell(col, r, out)?;
3736 }
3737 for (i, off) in field_offsets.iter().enumerate() {
3738 out[field_table_pos + i * 4..field_table_pos + i * 4 + 4].copy_from_slice(&off.to_le_bytes());
3739 }
3740 }
3741 for (i, off) in row_offsets.iter().enumerate() {
3742 out[row_table_pos + i * 4..row_table_pos + i * 4 + 4].copy_from_slice(&off.to_le_bytes());
3743 }
3744 Ok(())
3745}
3746
3747fn write_view_cell(col: &ListRepr, row: usize, out: &mut Vec<u8>) -> Result<(), String> {
3750 match col {
3751 ListRepr::Ints(v) => {
3752 out.push(T_INT);
3753 write_uvarint(zigzag(v[row]), out);
3754 }
3755 ListRepr::IntsI32(v) => {
3756 out.push(T_INT);
3757 write_uvarint(zigzag(v[row] as i64), out);
3758 }
3759 ListRepr::Floats(v) => {
3760 out.push(T_FLOAT);
3761 out.extend_from_slice(&v[row].to_le_bytes());
3762 }
3763 ListRepr::Bools(v) => out.push(if v[row] { T_TRUE } else { T_FALSE }),
3764 ListRepr::Strings { data, ends, .. } => {
3765 let start = if row == 0 { 0 } else { ends[row - 1] as usize };
3766 let end = ends[row] as usize;
3767 let s = &data[start..end];
3768 out.push(T_TEXT);
3769 write_uvarint(s.len() as u64, out);
3770 out.extend_from_slice(s);
3771 }
3772 other => native_encode(&other.get(row).ok_or("struct-view column row out of bounds")?, out)?,
3773 }
3774 Ok(())
3775}
3776
3777fn emit_structs_view_fixed(
3784 type_name: &str,
3785 field_names: &[String],
3786 columns: &[ListRepr],
3787 out: &mut Vec<u8>,
3788) -> Option<()> {
3789 let kinds = columns_fview_kinds(columns)?; let f = field_names.len();
3791 let n = columns.first().map_or(0, |c| c.len());
3792 let (_, stride) = fview_layout(&kinds);
3793 out.push(T_STRUCTS_FVIEW);
3794 write_str(type_name, out);
3795 write_uvarint(f as u64, out);
3796 for name in field_names {
3797 write_str(name, out);
3798 }
3799 out.extend_from_slice(&kinds);
3800 write_uvarint(n as u64, out);
3801 out.reserve(n.saturating_mul(stride));
3802 let mut blob: Vec<u8> = Vec::new();
3803 for r in 0..n {
3804 for col in columns {
3805 match col {
3806 ListRepr::Ints(v) => out.extend_from_slice(&v[r].to_le_bytes()),
3807 ListRepr::IntsI32(v) => out.extend_from_slice(&(v[r] as i64).to_le_bytes()),
3808 ListRepr::Floats(v) => out.extend_from_slice(&v[r].to_le_bytes()),
3809 ListRepr::Bools(v) => out.push(v[r] as u8),
3810 ListRepr::Strings { data, ends, .. } => {
3811 let start = if r == 0 { 0 } else { ends[r - 1] as usize };
3812 let end = ends[r] as usize;
3813 let off = blob.len() as u32;
3814 let len = (end - start) as u32;
3815 blob.extend_from_slice(&data[start..end]);
3816 out.extend_from_slice(&off.to_le_bytes());
3817 out.extend_from_slice(&len.to_le_bytes());
3818 }
3819 _ => unreachable!("non-fixed-viewable column passed the kind check"),
3821 }
3822 }
3823 }
3824 write_uvarint(blob.len() as u64, out);
3825 out.extend_from_slice(&blob);
3826 Some(())
3827}
3828
3829fn emit_aligned_i64(v: &[i64], out: &mut Vec<u8>) {
3834 out.push(T_INTS_ALIGNED);
3835 write_uvarint(v.len() as u64, out);
3836 let after_count = out.len();
3837 let pad = (14 - after_count % 8) % 8;
3838 out.push(pad as u8);
3839 out.resize(out.len() + pad, 0);
3840 #[cfg(target_endian = "little")]
3841 {
3842 let raw = unsafe { std::slice::from_raw_parts(v.as_ptr().cast::<u8>(), v.len() * 8) };
3844 out.extend_from_slice(raw);
3845 }
3846 #[cfg(target_endian = "big")]
3847 {
3848 out.reserve(v.len() * 8);
3849 for &n in v {
3850 out.extend_from_slice(&n.to_le_bytes());
3851 }
3852 }
3853}
3854
3855fn emit_aligned_f64(v: &[f64], out: &mut Vec<u8>) {
3857 out.push(T_FLOATS_ALIGNED);
3858 write_uvarint(v.len() as u64, out);
3859 let after_count = out.len();
3860 let pad = (14 - after_count % 8) % 8;
3861 out.push(pad as u8);
3862 out.resize(out.len() + pad, 0);
3863 #[cfg(target_endian = "little")]
3864 {
3865 let raw = unsafe { std::slice::from_raw_parts(v.as_ptr().cast::<u8>(), v.len() * 8) };
3867 out.extend_from_slice(raw);
3868 }
3869 #[cfg(target_endian = "big")]
3870 {
3871 out.reserve(v.len() * 8);
3872 for &x in v {
3873 out.extend_from_slice(&x.to_le_bytes());
3874 }
3875 }
3876}
3877
3878#[derive(Clone, Copy)]
3881pub enum WireColumn<'a> {
3882 Ints(&'a [i64]),
3884 Floats(&'a [f64]),
3886}
3887
3888pub fn build_columnar_record(from: &str, type_name: &str, fields: &[(&str, WireColumn)]) -> Vec<u8> {
3898 let mut fields: Vec<(&str, WireColumn)> = fields.to_vec();
3901 fields.sort_by(|a, b| a.0.cmp(b.0));
3902 let mut out = Vec::with_capacity(from.len() + type_name.len() + 32 + fields.len() * 64);
3903 write_str(from, &mut out);
3904 out.push(T_STRUCT_VIEW);
3905 write_str(type_name, &mut out);
3906 write_uvarint(fields.len() as u64, &mut out);
3907 for (name, _) in &fields {
3908 write_str(name, &mut out);
3909 }
3910 let table_pos = out.len();
3911 out.resize(table_pos + fields.len() * 4, 0);
3912 let values_start = out.len();
3913 let mut offsets: Vec<u32> = Vec::with_capacity(fields.len());
3914 for (_, col) in fields {
3915 offsets.push((out.len() - values_start) as u32);
3916 match col {
3917 WireColumn::Ints(d) => emit_aligned_i64(d, &mut out),
3918 WireColumn::Floats(d) => emit_aligned_f64(d, &mut out),
3919 }
3920 }
3921 for (i, off) in offsets.iter().enumerate() {
3922 out[table_pos + i * 4..table_pos + i * 4 + 4].copy_from_slice(&off.to_le_bytes());
3923 }
3924 frame(WireCodec::Native, current_integrity(), WireCompression::None, out)
3925}
3926
3927fn encode_list_repr(repr: &ListRepr, out: &mut Vec<u8>) -> Result<(), String> {
3932 let _depth = DepthGuard::enter()?;
3933 if flat_lists() {
3937 let values = repr.to_values();
3938 out.push(T_LIST);
3939 write_uvarint(values.len() as u64, out);
3940 for x in &values {
3941 native_encode(x, out)?;
3942 }
3943 return Ok(());
3944 }
3945 match repr {
3946 ListRepr::Ints(v) => {
3951 if struct_view_on() {
3952 emit_aligned_i64(v, out);
3953 return Ok(());
3954 }
3955 if structure() == WireStructure::Affine {
3956 if let Some((base, stride)) = detect_affine(v) {
3957 out.push(T_INTS_AFFINE);
3958 write_uvarint(zigzag(base), out);
3959 write_uvarint(zigzag(stride), out);
3960 write_uvarint(v.len() as u64, out);
3961 return Ok(());
3962 }
3963 }
3964 if structure() == WireStructure::Auto {
3965 emit_best_int_column(v, out);
3966 return Ok(());
3967 }
3968 match numerics() {
3969 WireNumerics::Varint => {
3970 out.push(T_INTS);
3971 leb128_encode(out, v.iter().copied(), v.len());
3972 }
3973 WireNumerics::Fixed => {
3974 out.push(T_INTS_FIXED);
3975 fixed_encode_i64(out, v);
3976 }
3977 WireNumerics::GroupVarint => {
3978 out.push(T_INTS_GV);
3979 gv_encode(out, v.iter().copied(), v.len());
3980 }
3981 }
3982 }
3983 ListRepr::IntsI32(v) => {
3984 if structure() == WireStructure::Auto {
3985 let widened: Vec<i64> = v.iter().map(|&n| n as i64).collect();
3986 emit_best_int_column(&widened, out);
3987 return Ok(());
3988 }
3989 match numerics() {
3990 WireNumerics::Varint => {
3991 out.push(T_INTS);
3992 leb128_encode(out, v.iter().map(|&n| n as i64), v.len());
3993 }
3994 WireNumerics::Fixed => {
3995 out.push(T_INTS_FIXED);
3996 write_uvarint(v.len() as u64, out);
3997 out.reserve(v.len() * 8);
3998 for &n in v {
3999 out.extend_from_slice(&(n as i64).to_le_bytes());
4000 }
4001 }
4002 WireNumerics::GroupVarint => {
4003 out.push(T_INTS_GV);
4004 gv_encode(out, v.iter().map(|&n| n as i64), v.len());
4005 }
4006 }
4007 }
4008 ListRepr::Floats(v) => {
4009 if struct_view_on() {
4010 emit_aligned_f64(v, out);
4011 return Ok(());
4012 }
4013 let st = structure();
4018 if matches!(st, WireStructure::Affine | WireStructure::Auto) {
4023 if let Some(bits) = detect_float_const(v) {
4024 out.push(T_FLOATS_CONST);
4025 out.extend_from_slice(&bits.to_le_bytes());
4026 write_uvarint(v.len() as u64, out);
4027 return Ok(());
4028 }
4029 if let Some((base, stride)) = detect_float_affine(v) {
4030 out.push(T_FLOATS_AFFINE);
4031 out.extend_from_slice(&base.to_le_bytes());
4032 out.extend_from_slice(&stride.to_le_bytes());
4033 write_uvarint(v.len() as u64, out);
4034 return Ok(());
4035 }
4036 }
4037 let sparse: Option<Vec<u8>> = if st == WireStructure::Auto {
4044 detect_float_sparse(v).map(|(dom, exc)| {
4045 let mut c = vec![T_FLOATS_SPARSE];
4046 c.extend_from_slice(&dom.to_le_bytes());
4047 write_uvarint(v.len() as u64, &mut c);
4048 write_uvarint(exc.len() as u64, &mut c);
4049 let mut prev = 0usize;
4050 for (i, bits) in &exc {
4051 write_uvarint((i - prev) as u64, &mut c);
4052 prev = *i;
4053 c.extend_from_slice(&bits.to_le_bytes());
4054 }
4055 c
4056 })
4057 } else {
4058 None
4059 };
4060 let xor: Option<Vec<u8>> = if floats_mode() == WireFloats::XorDelta {
4061 let mut body = Vec::with_capacity(v.len() + 2);
4062 floats_xor_encode(&mut body, v);
4063 if body.len() < floats_memcpy_body_len(v.len()) {
4064 let mut c = vec![T_FLOATS_XOR];
4065 c.extend_from_slice(&body);
4066 Some(c)
4067 } else {
4068 None
4069 }
4070 } else {
4071 None
4072 };
4073 let geometric: Option<Vec<u8>> = if st == WireStructure::Auto {
4074 detect_float_geometric(v).map(|(base, ratio)| {
4075 let mut c = vec![T_FLOATS_GEOMETRIC];
4076 c.extend_from_slice(&base.to_le_bytes());
4077 c.extend_from_slice(&ratio.to_le_bytes());
4078 write_uvarint(v.len() as u64, &mut c);
4079 c
4080 })
4081 } else {
4082 None
4083 };
4084 let periodic: Option<Vec<u8>> = if st == WireStructure::Auto {
4085 detect_float_period(v).map(|p| {
4086 let mut c = vec![T_FLOATS_PERIODIC];
4087 write_uvarint(p as u64, &mut c);
4088 write_uvarint(v.len() as u64, &mut c);
4089 for &x in &v[..p] {
4090 c.extend_from_slice(&x.to_le_bytes());
4091 }
4092 c
4093 })
4094 } else {
4095 None
4096 };
4097 if let Some(c) = [sparse, xor, geometric, periodic].into_iter().flatten().min_by_key(Vec::len) {
4098 if c.len() < floats_memcpy_body_len(v.len()) + 1 {
4100 out.extend_from_slice(&c);
4101 return Ok(());
4102 }
4103 }
4104 out.push(T_FLOATS);
4105 write_uvarint(v.len() as u64, out);
4106 #[cfg(target_endian = "little")]
4109 {
4110 let bytes = unsafe { std::slice::from_raw_parts(v.as_ptr().cast::<u8>(), std::mem::size_of_val(&v[..])) };
4112 out.extend_from_slice(bytes);
4113 }
4114 #[cfg(target_endian = "big")]
4115 {
4116 out.reserve(v.len() * 8);
4117 for &f in v {
4118 out.extend_from_slice(&f.to_le_bytes());
4119 }
4120 }
4121 }
4122 ListRepr::Bools(v) => {
4123 if structure() == WireStructure::Auto {
4126 emit_best_bool_column(v, out);
4127 } else {
4128 bool_bitpack(v, out);
4129 }
4130 }
4131 ListRepr::Strings { data, ends, .. } => {
4132 if structure() == WireStructure::Auto {
4135 emit_best_string_column(data, ends, out);
4136 } else {
4137 write_string_array_from_ends(out, data, ends);
4138 }
4139 }
4140 ListRepr::Structs { type_name, field_names, columns } => {
4143 let n = columns.first().map_or(0, |c| c.len());
4144 if struct_view_on() {
4145 if numerics() == WireNumerics::Fixed
4152 && emit_structs_view_fixed(type_name, field_names, columns, out).is_some()
4153 {
4154 return Ok(());
4155 }
4156 return emit_structs_view_columnar(type_name, field_names, columns, out);
4157 }
4158 emit_struct_list(type_name, field_names, n, out, |out| {
4159 for col in columns {
4160 encode_list_repr(col, out)?;
4161 }
4162 Ok(())
4163 })?;
4164 }
4165 ListRepr::Inductives { inductive_type, ctor_dict, ctors, ranks: _, arg_cols } => {
4170 out.push(T_INDUCTIVES);
4171 write_str(inductive_type, out);
4172 write_uvarint(ctor_dict.len() as u64, out);
4173 for (c, name) in ctor_dict.iter().enumerate() {
4174 write_str(name, out);
4175 write_uvarint(arg_cols[c].len() as u64, out); }
4177 let idx: Vec<i64> = ctors.iter().map(|&c| c as i64).collect();
4178 encode_list_repr(&ListRepr::Ints(idx), out)?;
4179 for cols in arg_cols {
4180 for col in cols {
4181 encode_list_repr(col, out)?;
4182 }
4183 }
4184 }
4185 ListRepr::WireStructs { .. } | ListRepr::WireColumn { .. } => {
4188 let materialized = ListRepr::from_values(repr.to_values());
4189 return encode_list_repr(&materialized, out);
4190 }
4191 ListRepr::Boxed(v) => {
4192 if !v.is_empty() && v.iter().all(|x| matches!(x, RuntimeValue::Text(_))) {
4193 let mut sdata = Vec::new();
4198 let mut sends = Vec::with_capacity(v.len());
4199 for x in v {
4200 if let RuntimeValue::Text(s) = x {
4201 sdata.extend_from_slice(s.as_bytes());
4202 sends.push(sdata.len() as u32);
4203 }
4204 }
4205 if structure() == WireStructure::Auto {
4206 emit_best_string_column(&sdata, &sends, out);
4207 } else {
4208 write_string_array_from_ends(out, &sdata, &sends);
4209 }
4210 } else if let Some((type_name, field_names)) = struct_schema(v) {
4211 if struct_view_on() {
4212 return emit_structs_view(&type_name, &field_names, v.len(), out, |row, fi| {
4215 match &v[row] {
4216 RuntimeValue::Struct(sv) => sv.fields.get(&field_names[fi]).cloned().unwrap(),
4217 _ => unreachable!("struct_schema guaranteed all-struct"),
4218 }
4219 });
4220 }
4221 emit_struct_list(&type_name, &field_names, v.len(), out, |out| {
4224 for fname in &field_names {
4225 let column: Vec<RuntimeValue> = v
4226 .iter()
4227 .map(|s| match s {
4228 RuntimeValue::Struct(sv) => sv.fields.get(fname).cloned().unwrap(),
4229 _ => unreachable!("struct_schema guaranteed all-struct"),
4230 })
4231 .collect();
4232 encode_list_repr(&ListRepr::from_values(column), out)?;
4233 }
4234 Ok(())
4235 })?;
4236 } else if let Some(ind) = ListRepr::build_inductives(v) {
4237 encode_list_repr(&ind, out)?;
4240 } else {
4241 out.push(T_LIST);
4243 write_uvarint(v.len() as u64, out);
4244 for x in v {
4245 native_encode(x, out)?;
4246 }
4247 }
4248 }
4249 }
4250 Ok(())
4251}
4252
4253#[inline(never)]
4256fn encode_money(m: &logicaffeine_base::Money, out: &mut Vec<u8>) {
4257 out.push(T_MONEY);
4258 let (negative, magnitude, scale) = m.amount.to_le_bytes();
4259 out.push(negative as u8);
4260 write_uvarint(magnitude.len() as u64, out);
4261 out.extend_from_slice(&magnitude);
4262 write_uvarint(scale as u64, out);
4263 let code = m.currency.code.as_bytes();
4264 write_uvarint(code.len() as u64, out);
4265 out.extend_from_slice(code);
4266}
4267
4268#[inline(never)]
4271fn decode_money(buf: &[u8], pos: &mut usize) -> Option<RuntimeValue> {
4272 let negative = *buf.get(*pos)? != 0;
4273 *pos += 1;
4274 let len = read_uvarint(buf, pos)? as usize;
4275 let bytes = buf.get(*pos..pos.checked_add(len)?)?;
4276 *pos += len;
4277 let scale = u32::try_from(read_uvarint(buf, pos)?).ok()?;
4278 let amount = logicaffeine_base::Decimal::from_le_bytes(negative, bytes, scale);
4279 let clen = read_uvarint(buf, pos)? as usize;
4280 let cbytes = buf.get(*pos..pos.checked_add(clen)?)?;
4281 *pos += clen;
4282 let code = std::str::from_utf8(cbytes).ok()?;
4283 let currency = logicaffeine_base::money::currency::by_code(code)
4284 .unwrap_or(logicaffeine_base::Currency { code: "XXX", scale: 0 });
4285 Some(RuntimeValue::Money(Rc::new(logicaffeine_base::Money { amount, currency })))
4286}
4287
4288fn encode_uuid(u: &logicaffeine_base::Uuid, out: &mut Vec<u8>) {
4290 out.push(T_UUID);
4291 out.extend_from_slice(u.as_bytes());
4292}
4293
4294fn decode_uuid(buf: &[u8], pos: &mut usize) -> Option<RuntimeValue> {
4296 let bytes = buf.get(*pos..pos.checked_add(16)?)?;
4297 *pos += 16;
4298 let mut arr = [0u8; 16];
4299 arr.copy_from_slice(bytes);
4300 Some(RuntimeValue::Uuid(Rc::new(logicaffeine_base::Uuid::from_bytes(arr))))
4301}
4302
4303fn native_encode(v: &RuntimeValue, out: &mut Vec<u8>) -> Result<(), String> {
4306 let _depth = DepthGuard::enter()?;
4307 if dedup_encode_prefix(v, out) {
4311 return Ok(());
4312 }
4313 match v {
4314 RuntimeValue::Nothing => out.push(T_NOTHING),
4315 RuntimeValue::Bool(false) => out.push(T_FALSE),
4316 RuntimeValue::Bool(true) => out.push(T_TRUE),
4317 RuntimeValue::Int(n) => {
4318 out.push(T_INT);
4319 write_uvarint(zigzag(*n), out);
4320 }
4321 RuntimeValue::Word(w) => {
4322 out.push(T_WORD);
4323 out.push(w.width() as u8);
4324 write_uvarint(w.to_u64(), out);
4325 }
4326 RuntimeValue::Lanes(_) => {
4327 return Err("a SIMD lane vector is a transient compute value, not a wire type".to_string());
4328 }
4329 RuntimeValue::BigInt(b) => {
4332 out.push(T_BIGINT);
4333 let (negative, magnitude) = b.to_le_bytes();
4334 out.push(negative as u8);
4335 write_uvarint(magnitude.len() as u64, out);
4336 out.extend_from_slice(&magnitude);
4337 }
4338 RuntimeValue::Rational(r) => {
4341 out.push(T_RATIONAL);
4342 let (num_negative, num_magnitude) = r.numerator().to_le_bytes();
4343 out.push(num_negative as u8);
4344 write_uvarint(num_magnitude.len() as u64, out);
4345 out.extend_from_slice(&num_magnitude);
4346 let (_den_sign, den_magnitude) = r.denominator().to_le_bytes();
4347 write_uvarint(den_magnitude.len() as u64, out);
4348 out.extend_from_slice(&den_magnitude);
4349 }
4350 RuntimeValue::Decimal(d) => {
4353 out.push(T_DECIMAL);
4354 let (negative, magnitude, scale) = d.to_le_bytes();
4355 out.push(negative as u8);
4356 write_uvarint(magnitude.len() as u64, out);
4357 out.extend_from_slice(&magnitude);
4358 write_uvarint(scale as u64, out);
4359 }
4360 RuntimeValue::Money(m) => encode_money(m, out),
4364 RuntimeValue::Uuid(u) => encode_uuid(u, out),
4365 RuntimeValue::Complex(c) => {
4368 out.push(T_COMPLEX);
4369 for part in [c.re(), c.im()] {
4370 let (neg, num) = part.numerator().to_le_bytes();
4371 out.push(neg as u8);
4372 write_uvarint(num.len() as u64, out);
4373 out.extend_from_slice(&num);
4374 let (_den_sign, den) = part.denominator().to_le_bytes();
4375 write_uvarint(den.len() as u64, out);
4376 out.extend_from_slice(&den);
4377 }
4378 }
4379 RuntimeValue::Modular(m) => {
4381 out.push(T_MODULAR);
4382 let (_, value) = m.value().to_le_bytes();
4383 write_uvarint(value.len() as u64, out);
4384 out.extend_from_slice(&value);
4385 let (_, modulus) = m.modulus().to_le_bytes();
4386 write_uvarint(modulus.len() as u64, out);
4387 out.extend_from_slice(&modulus);
4388 }
4389 RuntimeValue::Float(f) => {
4390 out.push(T_FLOAT);
4391 out.extend_from_slice(&f.to_le_bytes());
4392 }
4393 RuntimeValue::Char(c) => {
4394 out.push(T_CHAR);
4395 write_uvarint(*c as u64, out);
4396 }
4397 RuntimeValue::Text(s) => {
4398 out.push(T_TEXT);
4399 write_str(s, out);
4400 }
4401 RuntimeValue::Duration(n) => {
4402 out.push(T_DURATION);
4403 write_uvarint(zigzag(*n), out);
4404 }
4405 RuntimeValue::Date(n) => {
4406 out.push(T_DATE);
4407 write_uvarint(zigzag(*n as i64), out);
4408 }
4409 RuntimeValue::Moment(n) => {
4410 out.push(T_MOMENT);
4411 write_uvarint(zigzag(*n), out);
4412 }
4413 RuntimeValue::Span { months, days } => {
4414 out.push(T_SPAN);
4415 write_uvarint(zigzag(*months as i64), out);
4416 write_uvarint(zigzag(*days as i64), out);
4417 }
4418 RuntimeValue::Time(n) => {
4419 out.push(T_TIME);
4420 write_uvarint(zigzag(*n), out);
4421 }
4422 RuntimeValue::Peer(topic) => {
4423 out.push(T_PEER);
4424 write_str(topic, out);
4425 }
4426 RuntimeValue::List(items) => encode_list_repr(&items.borrow(), out)?,
4427 RuntimeValue::Tuple(items) => {
4428 out.push(T_TUPLE);
4429 write_uvarint(items.len() as u64, out);
4430 for x in items.iter() {
4431 native_encode(x, out)?;
4432 }
4433 }
4434 RuntimeValue::Set(items) => {
4435 let b = items.borrow();
4436 if !b.is_empty() && b.iter().all(|x| matches!(x, RuntimeValue::Int(_))) {
4437 let mut ints: Vec<i64> = b
4442 .iter()
4443 .map(|x| if let RuntimeValue::Int(n) = x { *n } else { unreachable!() })
4444 .collect();
4445 ints.sort_unstable();
4446 ints.dedup();
4447 out.push(T_SET_INTS);
4448 emit_best_int_column(&ints, out);
4449 } else if !b.is_empty() && b.iter().all(|x| matches!(x, RuntimeValue::Text(_))) {
4450 let mut strs: Vec<String> = b
4455 .iter()
4456 .map(|x| if let RuntimeValue::Text(t) = x { (**t).clone() } else { unreachable!() })
4457 .collect();
4458 strs.sort_unstable();
4459 strs.dedup();
4460 out.push(T_SET_STRINGS);
4461 write_uvarint(strs.len() as u64, out);
4462 let mut prev: &str = "";
4463 for s in &strs {
4464 let common: usize = s
4466 .chars()
4467 .zip(prev.chars())
4468 .take_while(|(a, b)| a == b)
4469 .map(|(a, _)| a.len_utf8())
4470 .sum();
4471 write_uvarint(common as u64, out);
4472 write_str(&s[common..], out);
4473 prev = s;
4474 }
4475 } else {
4476 out.push(T_SET);
4482 let mut encoded: Vec<Vec<u8>> = Vec::with_capacity(b.len());
4483 for x in b.iter() {
4484 let mut xb = Vec::new();
4485 native_encode(x, &mut xb)?;
4486 encoded.push(xb);
4487 }
4488 encoded.sort_unstable();
4489 write_uvarint(encoded.len() as u64, out);
4490 for xb in &encoded {
4491 out.extend_from_slice(xb);
4492 }
4493 }
4494 }
4495 RuntimeValue::Map(m) => {
4496 let b = m.borrow();
4497 if !b.is_empty() && b.keys().all(|k| matches!(k, RuntimeValue::Int(_))) {
4498 let mut pairs: Vec<(i64, RuntimeValue)> = b
4504 .iter()
4505 .map(|(k, v)| match k {
4506 RuntimeValue::Int(n) => (*n, v.clone()),
4507 _ => unreachable!("all keys verified Int"),
4508 })
4509 .collect();
4510 pairs.sort_by_key(|(k, _)| *k);
4511 let keys: Vec<i64> = pairs.iter().map(|(k, _)| *k).collect();
4512 let vals: Vec<RuntimeValue> = pairs.into_iter().map(|(_, v)| v).collect();
4513 out.push(T_MAP_INTKEY);
4514 emit_best_int_column(&keys, out);
4515 if vals.iter().all(|v| matches!(v, RuntimeValue::Int(_))) {
4520 out.push(1u8);
4521 let int_vals: Vec<i64> = vals
4522 .iter()
4523 .map(|v| match v {
4524 RuntimeValue::Int(n) => *n,
4525 _ => unreachable!("all values verified Int"),
4526 })
4527 .collect();
4528 emit_best_int_column(&int_vals, out);
4529 } else if vals.iter().all(|v| matches!(v, RuntimeValue::Text(_))) {
4530 out.push(2u8);
4536 write_uvarint(vals.len() as u64, out);
4537 let mut prev: &str = "";
4538 for v in &vals {
4539 let s = match v {
4540 RuntimeValue::Text(t) => t.as_str(),
4541 _ => unreachable!("all values verified Text"),
4542 };
4543 let common: usize = s
4544 .chars()
4545 .zip(prev.chars())
4546 .take_while(|(a, b)| a == b)
4547 .map(|(a, _)| a.len_utf8())
4548 .sum();
4549 write_uvarint(common as u64, out);
4550 write_str(&s[common..], out);
4551 prev = s;
4552 }
4553 } else if vals.iter().all(|v| matches!(v, RuntimeValue::Struct(_))) {
4554 out.push(3u8);
4560 let vlist = RuntimeValue::List(Rc::new(RefCell::new(ListRepr::from_values(vals.clone()))));
4561 native_encode(&vlist, out)?;
4562 } else {
4563 out.push(0u8);
4564 write_uvarint(vals.len() as u64, out);
4565 for v in &vals {
4566 native_encode(v, out)?;
4567 }
4568 }
4569 } else {
4570 out.push(T_MAP);
4571 let mut entries: Vec<(Vec<u8>, Vec<u8>)> = Vec::with_capacity(b.len());
4573 for (k, val) in b.iter() {
4574 let mut kb = Vec::new();
4575 native_encode(k, &mut kb)?;
4576 let mut vb = Vec::new();
4577 native_encode(val, &mut vb)?;
4578 entries.push((kb, vb));
4579 }
4580 entries.sort_by(|a, b| a.0.cmp(&b.0));
4581 write_uvarint(entries.len() as u64, out);
4582 for (kb, vb) in entries {
4583 out.extend_from_slice(&kb);
4584 out.extend_from_slice(&vb);
4585 }
4586 }
4587 }
4588 RuntimeValue::Struct(s) => {
4589 let mut fields: Vec<(&String, &RuntimeValue)> = s.fields.iter().collect();
4595 fields.sort_by(|a, b| a.0.cmp(b.0));
4596 let field_names: Vec<String> = fields.iter().map(|(n, _)| (*n).clone()).collect();
4597 if struct_view_on() {
4598 out.push(T_STRUCT_VIEW);
4602 write_str(&s.type_name, out);
4603 write_uvarint(fields.len() as u64, out);
4604 for (name, _) in &fields {
4605 write_str(name, out);
4606 }
4607 let table_pos = out.len();
4608 out.resize(table_pos + fields.len() * 4, 0);
4609 let values_start = out.len();
4610 let mut offsets: Vec<u32> = Vec::with_capacity(fields.len());
4611 for (_, val) in &fields {
4612 offsets.push((out.len() - values_start) as u32);
4613 native_encode(val, out)?;
4614 }
4615 for (i, off) in offsets.iter().enumerate() {
4616 out[table_pos + i * 4..table_pos + i * 4 + 4].copy_from_slice(&off.to_le_bytes());
4617 }
4618 } else if let Some(id) = type_registry_id(&s.type_name, &field_names) {
4619 out.push(T_STRUCT_TID);
4623 write_uvarint(id as u64, out);
4624 for (_, val) in &fields {
4625 native_encode(val, out)?;
4626 }
4627 } else {
4628 match schema_send(&s.type_name, &field_names) {
4629 SchemaEmit::Inline => {
4630 out.push(T_STRUCT);
4631 write_str(&s.type_name, out);
4632 write_uvarint(fields.len() as u64, out);
4633 for (name, val) in &fields {
4634 write_str(name, out);
4635 native_encode(val, out)?;
4636 }
4637 }
4638 SchemaEmit::SeqDef(id) => {
4639 out.push(T_STRUCT_DEF);
4640 write_uvarint(id as u64, out);
4641 write_struct_schema(&s.type_name, &field_names, out);
4642 for (_, val) in &fields {
4643 native_encode(val, out)?;
4644 }
4645 }
4646 SchemaEmit::SeqRef(id) => {
4647 out.push(T_STRUCT_REF);
4648 write_uvarint(id as u64, out);
4649 for (_, val) in &fields {
4650 native_encode(val, out)?;
4651 }
4652 }
4653 SchemaEmit::CaDef => {
4654 out.push(T_STRUCT_CDEF);
4655 write_struct_schema(&s.type_name, &field_names, out);
4656 for (_, val) in &fields {
4657 native_encode(val, out)?;
4658 }
4659 }
4660 SchemaEmit::CaRef(fp) => {
4661 out.push(T_STRUCT_CREF);
4662 out.extend_from_slice(&fp.to_le_bytes());
4663 for (_, val) in &fields {
4664 native_encode(val, out)?;
4665 }
4666 }
4667 }
4668 }
4669 }
4670 RuntimeValue::Inductive(ind) => {
4671 if let Some((enum_id, ctor_idx)) = type_registry_enum_id(&ind.inductive_type, &ind.constructor) {
4672 out.push(T_INDUCTIVE_TID);
4675 write_uvarint(enum_id as u64, out);
4676 write_uvarint(ctor_idx as u64, out);
4677 write_uvarint(ind.args.len() as u64, out);
4678 for a in &ind.args {
4679 native_encode(a, out)?;
4680 }
4681 } else {
4682 out.push(T_INDUCTIVE);
4683 write_str(&ind.inductive_type, out);
4684 write_str(&ind.constructor, out);
4685 write_uvarint(ind.args.len() as u64, out);
4686 for a in &ind.args {
4687 native_encode(a, out)?;
4688 }
4689 }
4690 }
4691 RuntimeValue::Chan(_) | RuntimeValue::TaskHandle(_) => {
4692 return Err("a channel or task handle cannot be sent over the network".to_string());
4693 }
4694 RuntimeValue::Crdt(_) => {
4695 return Err("a CRDT value is shared via Merge/Sync, not sent inline".to_string());
4696 }
4697 RuntimeValue::Function(f) => {
4698 match &f.generated {
4702 Some(expr) => {
4703 out.push(T_FUNC);
4704 write_uvarint(f.param_names.len() as u64, out);
4705 serialize_gen(expr, out);
4706 }
4707 None => return Err("a Function cannot be sent over the network".to_string()),
4708 }
4709 }
4710 RuntimeValue::Quantity(qv) => {
4713 out.push(T_QUANTITY);
4714 let (num_negative, num_magnitude) = qv.q.magnitude_si().numerator().to_le_bytes();
4715 out.push(num_negative as u8);
4716 write_uvarint(num_magnitude.len() as u64, out);
4717 out.extend_from_slice(&num_magnitude);
4718 let (_den_sign, den_magnitude) = qv.q.magnitude_si().denominator().to_le_bytes();
4719 write_uvarint(den_magnitude.len() as u64, out);
4720 out.extend_from_slice(&den_magnitude);
4721 let dim = qv.q.dimension();
4722 for d in logicaffeine_base::BaseDim::ALL {
4723 let e = dim.exponent(d);
4724 write_uvarint(zigzag(e.numerator() as i64), out);
4725 write_uvarint(zigzag(e.denominator() as i64), out);
4726 }
4727 let sym = qv.unit.symbol.as_bytes();
4728 write_uvarint(sym.len() as u64, out);
4729 out.extend_from_slice(sym);
4730 }
4731 }
4732 Ok(())
4733}
4734
4735const PREALLOC_CAP: usize = 4096;
4738
4739fn bounded_count(n: u64) -> Option<usize> {
4745 let n = n as usize;
4746 (n <= receive_limits().max_elements).then_some(n)
4747}
4748
4749fn native_decode(buf: &[u8], pos: &mut usize) -> Option<RuntimeValue> {
4750 let _depth = DecodeDepthGuard::enter()?;
4753 let tag = *buf.get(*pos)?;
4754 *pos += 1;
4755 if tag == T_SHARED_REF {
4758 let id = read_uvarint(buf, pos)?;
4759 return DECODE_MEMO.with(|c| c.borrow().get(&id).cloned());
4760 }
4761 if tag == T_SHARED_DEF {
4762 let id = read_uvarint(buf, pos)?;
4763 let v = native_decode(buf, pos)?;
4764 DECODE_MEMO.with(|c| c.borrow_mut().insert(id, v.clone()));
4765 return Some(v);
4766 }
4767 Some(match tag {
4768 T_NOTHING => RuntimeValue::Nothing,
4769 T_FALSE => RuntimeValue::Bool(false),
4770 T_TRUE => RuntimeValue::Bool(true),
4771 T_INT => RuntimeValue::Int(unzigzag(read_uvarint(buf, pos)?)),
4772 T_WORD => {
4773 let width = *buf.get(*pos)? as u32;
4774 *pos += 1;
4775 let bits = read_uvarint(buf, pos)?;
4776 RuntimeValue::Word(logicaffeine_base::WordVal::from_u64(width, bits)?)
4777 }
4778 T_BIGINT => {
4779 let negative = *buf.get(*pos)? != 0;
4780 *pos += 1;
4781 let len = read_uvarint(buf, pos)? as usize;
4782 let bytes = buf.get(*pos..pos.checked_add(len)?)?;
4783 *pos += len;
4784 RuntimeValue::from_bigint(logicaffeine_base::BigInt::from_le_bytes(negative, bytes))
4785 }
4786 T_RATIONAL => {
4787 let num_negative = *buf.get(*pos)? != 0;
4788 *pos += 1;
4789 let num_len = read_uvarint(buf, pos)? as usize;
4790 let num_bytes = buf.get(*pos..pos.checked_add(num_len)?)?;
4791 *pos += num_len;
4792 let num = logicaffeine_base::BigInt::from_le_bytes(num_negative, num_bytes);
4793 let den_len = read_uvarint(buf, pos)? as usize;
4794 let den_bytes = buf.get(*pos..pos.checked_add(den_len)?)?;
4795 *pos += den_len;
4796 let den = logicaffeine_base::BigInt::from_le_bytes(false, den_bytes);
4797 RuntimeValue::from_rational(logicaffeine_base::Rational::new(num, den)?)
4799 }
4800 T_DECIMAL => {
4801 let negative = *buf.get(*pos)? != 0;
4802 *pos += 1;
4803 let len = read_uvarint(buf, pos)? as usize;
4804 let bytes = buf.get(*pos..pos.checked_add(len)?)?;
4805 *pos += len;
4806 let scale = u32::try_from(read_uvarint(buf, pos)?).ok()?;
4807 RuntimeValue::Decimal(Rc::new(logicaffeine_base::Decimal::from_le_bytes(
4810 negative, bytes, scale,
4811 )))
4812 }
4813 T_MONEY => decode_money(buf, pos)?,
4815 T_UUID => decode_uuid(buf, pos)?,
4816 T_COMPLEX => {
4817 let re_neg = *buf.get(*pos)? != 0;
4819 *pos += 1;
4820 let re_nlen = read_uvarint(buf, pos)? as usize;
4821 let re_nb = buf.get(*pos..pos.checked_add(re_nlen)?)?;
4822 *pos += re_nlen;
4823 let re_num = logicaffeine_base::BigInt::from_le_bytes(re_neg, re_nb);
4824 let re_dlen = read_uvarint(buf, pos)? as usize;
4825 let re_db = buf.get(*pos..pos.checked_add(re_dlen)?)?;
4826 *pos += re_dlen;
4827 let re = logicaffeine_base::Rational::new(re_num, logicaffeine_base::BigInt::from_le_bytes(false, re_db))?;
4828 let im_neg = *buf.get(*pos)? != 0;
4829 *pos += 1;
4830 let im_nlen = read_uvarint(buf, pos)? as usize;
4831 let im_nb = buf.get(*pos..pos.checked_add(im_nlen)?)?;
4832 *pos += im_nlen;
4833 let im_num = logicaffeine_base::BigInt::from_le_bytes(im_neg, im_nb);
4834 let im_dlen = read_uvarint(buf, pos)? as usize;
4835 let im_db = buf.get(*pos..pos.checked_add(im_dlen)?)?;
4836 *pos += im_dlen;
4837 let im = logicaffeine_base::Rational::new(im_num, logicaffeine_base::BigInt::from_le_bytes(false, im_db))?;
4838 RuntimeValue::Complex(Rc::new(logicaffeine_base::Complex::new(re, im)))
4839 }
4840 T_MODULAR => {
4841 let vlen = read_uvarint(buf, pos)? as usize;
4842 let vb = buf.get(*pos..pos.checked_add(vlen)?)?;
4843 *pos += vlen;
4844 let v = logicaffeine_base::BigInt::from_le_bytes(false, vb);
4845 let nlen = read_uvarint(buf, pos)? as usize;
4846 let nb = buf.get(*pos..pos.checked_add(nlen)?)?;
4847 *pos += nlen;
4848 let n = logicaffeine_base::BigInt::from_le_bytes(false, nb);
4849 RuntimeValue::Modular(Rc::new(logicaffeine_base::Modular::new(v, n)?))
4850 }
4851 T_QUANTITY => {
4852 let num_neg = *buf.get(*pos)? != 0;
4854 *pos += 1;
4855 let nlen = read_uvarint(buf, pos)? as usize;
4856 let nb = buf.get(*pos..pos.checked_add(nlen)?)?;
4857 *pos += nlen;
4858 let num = logicaffeine_base::BigInt::from_le_bytes(num_neg, nb);
4859 let dlen = read_uvarint(buf, pos)? as usize;
4860 let db = buf.get(*pos..pos.checked_add(dlen)?)?;
4861 *pos += dlen;
4862 let magnitude =
4863 logicaffeine_base::Rational::new(num, logicaffeine_base::BigInt::from_le_bytes(false, db))?;
4864 let mut exps = [logicaffeine_base::Exp::ZERO; logicaffeine_base::BaseDim::COUNT];
4866 for slot in exps.iter_mut() {
4867 let en = unzigzag(read_uvarint(buf, pos)?) as i32;
4868 let ed = unzigzag(read_uvarint(buf, pos)?) as i32;
4869 *slot = logicaffeine_base::Exp::new(en, if ed == 0 { 1 } else { ed });
4870 }
4871 let dim = logicaffeine_base::Dimension::from_exps(exps);
4872 let sym = read_str(buf, pos)?;
4874 let unit = logicaffeine_base::quantity::units::by_name(&sym)
4875 .filter(|u| u.dimension == dim)
4876 .unwrap_or_else(|| {
4877 logicaffeine_base::Unit::linear("", dim, logicaffeine_base::Rational::one())
4878 });
4879 RuntimeValue::Quantity(Rc::new(crate::interpreter::QuantityValue {
4880 q: logicaffeine_base::Quantity::si(magnitude, dim),
4881 unit,
4882 }))
4883 }
4884 T_FLOAT => {
4885 let b: [u8; 8] = buf.get(*pos..pos.checked_add(8)?)?.try_into().ok()?;
4886 *pos += 8;
4887 RuntimeValue::Float(f64::from_le_bytes(b))
4888 }
4889 T_CHAR => RuntimeValue::Char(char::from_u32(u32::try_from(read_uvarint(buf, pos)?).ok()?)?),
4890 T_TEXT => RuntimeValue::Text(Rc::new(read_str(buf, pos)?)),
4891 T_DURATION => RuntimeValue::Duration(unzigzag(read_uvarint(buf, pos)?)),
4892 T_DATE => RuntimeValue::Date(i32::try_from(unzigzag(read_uvarint(buf, pos)?)).ok()?),
4893 T_MOMENT => RuntimeValue::Moment(unzigzag(read_uvarint(buf, pos)?)),
4894 T_SPAN => RuntimeValue::Span {
4895 months: i32::try_from(unzigzag(read_uvarint(buf, pos)?)).ok()?,
4896 days: i32::try_from(unzigzag(read_uvarint(buf, pos)?)).ok()?,
4897 },
4898 T_TIME => RuntimeValue::Time(unzigzag(read_uvarint(buf, pos)?)),
4899 T_PEER => RuntimeValue::Peer(Rc::new(read_str(buf, pos)?)),
4900 T_LIST => RuntimeValue::List(Rc::new(RefCell::new(ListRepr::Boxed(read_seq(buf, pos)?)))),
4903 T_INTS
4904 | T_INTS_AFFINE
4905 | T_INTS_GEOMETRIC
4906 | T_INTS_PERIODIC
4907 | T_INTS_SPARSE
4908 | T_INTS_POLY
4909 | T_GEN
4910 | T_BYTES
4911 | T_INTS_DELTA
4912 | T_INTS_DOD
4913 | T_INTS_FOR
4914 | T_INTS_RLE
4915 | T_INTS_DICT
4916 | describe::T_INTS_LRECUR
4917 | describe::T_INTS_LFSR
4918 | describe::T_INTS_FCSR => {
4919 let v = describe::decode_int_column_body(tag, buf, pos, receive_limits().max_elements, 0)?;
4922 RuntimeValue::List(Rc::new(RefCell::new(ListRepr::Ints(v))))
4923 }
4924 T_INTS_GV => RuntimeValue::List(Rc::new(RefCell::new(ListRepr::Ints(gv_decode_dispatch(buf, pos)?)))),
4925 T_FUNC => {
4928 if !receive_limits().accept_computed {
4929 return None;
4930 }
4931 let arity = read_uvarint(buf, pos)? as usize;
4932 if arity > 16 {
4933 return None;
4934 }
4935 let mut budget = MAX_GEN_NODES;
4936 let expr = deserialize_gen(buf, pos, &mut budget, 0)?;
4937 let param_names: Vec<logicaffeine_base::Symbol> =
4938 (0..arity).map(logicaffeine_base::Symbol::from_index).collect();
4939 RuntimeValue::Function(Box::new(ClosureValue {
4940 body_index: usize::MAX,
4941 captured_env: std::collections::HashMap::default(),
4942 param_names,
4943 generated: Some(Rc::new(expr)),
4944 }))
4945 }
4946 T_INTS_FIXED => {
4947 let n = read_uvarint(buf, pos)? as usize;
4948 let nbytes = n.checked_mul(8)?;
4949 let raw = buf.get(*pos..pos.checked_add(nbytes)?)?;
4950 *pos += nbytes;
4951 #[cfg(target_endian = "little")]
4954 let v: Vec<i64> = {
4955 let mut v = Vec::<i64>::with_capacity(n);
4956 unsafe {
4959 std::ptr::copy_nonoverlapping(raw.as_ptr(), v.as_mut_ptr().cast::<u8>(), nbytes);
4960 v.set_len(n);
4961 }
4962 v
4963 };
4964 #[cfg(target_endian = "big")]
4965 let v: Vec<i64> = raw
4966 .chunks_exact(8)
4967 .map(|c| i64::from_le_bytes(c.try_into().unwrap()))
4968 .collect();
4969 RuntimeValue::List(Rc::new(RefCell::new(ListRepr::Ints(v))))
4970 }
4971 T_INTS_ALIGNED => {
4973 let n = read_uvarint(buf, pos)? as usize;
4974 let pad = *buf.get(*pos)? as usize;
4975 *pos += 1 + pad;
4976 let nbytes = n.checked_mul(8)?;
4977 let raw = buf.get(*pos..pos.checked_add(nbytes)?)?;
4978 *pos += nbytes;
4979 #[cfg(target_endian = "little")]
4980 let v: Vec<i64> = {
4981 let mut v = Vec::<i64>::with_capacity(n);
4982 unsafe {
4985 std::ptr::copy_nonoverlapping(raw.as_ptr(), v.as_mut_ptr().cast::<u8>(), nbytes);
4986 v.set_len(n);
4987 }
4988 v
4989 };
4990 #[cfg(target_endian = "big")]
4991 let v: Vec<i64> = raw.chunks_exact(8).map(|c| i64::from_le_bytes(c.try_into().unwrap())).collect();
4992 RuntimeValue::List(Rc::new(RefCell::new(ListRepr::Ints(v))))
4993 }
4994 T_FLOATS => {
4995 let n = bounded_count(read_uvarint(buf, pos)?)?;
4996 let nbytes = n.checked_mul(8)?;
4997 let raw = buf.get(*pos..pos.checked_add(nbytes)?)?;
4998 *pos += nbytes;
4999 #[cfg(target_endian = "little")]
5003 let v: Vec<f64> = {
5004 let mut v = Vec::<f64>::with_capacity(n);
5005 unsafe {
5008 std::ptr::copy_nonoverlapping(raw.as_ptr(), v.as_mut_ptr().cast::<u8>(), nbytes);
5009 v.set_len(n);
5010 }
5011 v
5012 };
5013 #[cfg(target_endian = "big")]
5014 let v: Vec<f64> = raw
5015 .chunks_exact(8)
5016 .map(|c| f64::from_le_bytes(c.try_into().unwrap()))
5017 .collect();
5018 RuntimeValue::List(Rc::new(RefCell::new(ListRepr::Floats(v))))
5019 }
5020 T_FLOATS_CONST => {
5022 let bits = u64::from_le_bytes(buf.get(*pos..pos.checked_add(8)?)?.try_into().ok()?);
5023 *pos += 8;
5024 let n = bounded_count(read_uvarint(buf, pos)?)?;
5025 let mut v = Vec::with_capacity(n.min(PREALLOC_CAP));
5026 v.resize(n, f64::from_bits(bits));
5027 RuntimeValue::List(Rc::new(RefCell::new(ListRepr::Floats(v))))
5028 }
5029 T_FLOATS_AFFINE => {
5032 let base = f64::from_le_bytes(buf.get(*pos..pos.checked_add(8)?)?.try_into().ok()?);
5033 *pos += 8;
5034 let stride = f64::from_le_bytes(buf.get(*pos..pos.checked_add(8)?)?.try_into().ok()?);
5035 *pos += 8;
5036 let n = bounded_count(read_uvarint(buf, pos)?)?;
5037 let mut v = Vec::with_capacity(n.min(PREALLOC_CAP));
5038 for i in 0..n {
5039 v.push(base + (i as f64) * stride);
5040 }
5041 RuntimeValue::List(Rc::new(RefCell::new(ListRepr::Floats(v))))
5042 }
5043 T_FLOATS_SPARSE => {
5045 let dom = f64::from_bits(u64::from_le_bytes(buf.get(*pos..pos.checked_add(8)?)?.try_into().ok()?));
5046 *pos += 8;
5047 let n = bounded_count(read_uvarint(buf, pos)?)?;
5048 let num_exc = bounded_count(read_uvarint(buf, pos)?)?;
5049 let mut v = Vec::with_capacity(n.min(PREALLOC_CAP));
5050 v.resize(n, dom);
5051 let mut idx = 0usize;
5052 for _ in 0..num_exc {
5053 idx = idx.checked_add(read_uvarint(buf, pos)? as usize)?;
5054 let bits = u64::from_le_bytes(buf.get(*pos..pos.checked_add(8)?)?.try_into().ok()?);
5055 *pos += 8;
5056 *v.get_mut(idx)? = f64::from_bits(bits);
5057 }
5058 RuntimeValue::List(Rc::new(RefCell::new(ListRepr::Floats(v))))
5059 }
5060 T_FLOATS_PERIODIC => {
5062 let p = bounded_count(read_uvarint(buf, pos)?)?;
5063 if p == 0 {
5064 return None;
5065 }
5066 let n = bounded_count(read_uvarint(buf, pos)?)?;
5067 let mut block = Vec::with_capacity(p.min(PREALLOC_CAP));
5068 for _ in 0..p {
5069 let bits = u64::from_le_bytes(buf.get(*pos..pos.checked_add(8)?)?.try_into().ok()?);
5070 *pos += 8;
5071 block.push(f64::from_bits(bits));
5072 }
5073 let mut v = Vec::with_capacity(n.min(PREALLOC_CAP));
5074 for i in 0..n {
5075 v.push(block[i % p]);
5076 }
5077 RuntimeValue::List(Rc::new(RefCell::new(ListRepr::Floats(v))))
5078 }
5079 T_FLOATS_GEOMETRIC => {
5082 let base = f64::from_le_bytes(buf.get(*pos..pos.checked_add(8)?)?.try_into().ok()?);
5083 *pos += 8;
5084 let ratio = f64::from_le_bytes(buf.get(*pos..pos.checked_add(8)?)?.try_into().ok()?);
5085 *pos += 8;
5086 let n = bounded_count(read_uvarint(buf, pos)?)?;
5087 let mut v = Vec::with_capacity(n.min(PREALLOC_CAP));
5088 let mut cur = base;
5089 for _ in 0..n {
5090 v.push(cur);
5091 cur *= ratio;
5092 }
5093 RuntimeValue::List(Rc::new(RefCell::new(ListRepr::Floats(v))))
5094 }
5095 T_FLOATS_ALIGNED => {
5097 let n = read_uvarint(buf, pos)? as usize;
5098 let pad = *buf.get(*pos)? as usize;
5099 *pos += 1 + pad;
5100 let nbytes = n.checked_mul(8)?;
5101 let raw = buf.get(*pos..pos.checked_add(nbytes)?)?;
5102 *pos += nbytes;
5103 #[cfg(target_endian = "little")]
5104 let v: Vec<f64> = {
5105 let mut v = Vec::<f64>::with_capacity(n);
5106 unsafe {
5109 std::ptr::copy_nonoverlapping(raw.as_ptr(), v.as_mut_ptr().cast::<u8>(), nbytes);
5110 v.set_len(n);
5111 }
5112 v
5113 };
5114 #[cfg(target_endian = "big")]
5115 let v: Vec<f64> = raw.chunks_exact(8).map(|c| f64::from_le_bytes(c.try_into().unwrap())).collect();
5116 RuntimeValue::List(Rc::new(RefCell::new(ListRepr::Floats(v))))
5117 }
5118 T_FLOATS_XOR => {
5121 let n = read_uvarint(buf, pos)? as usize;
5122 let mut v = Vec::with_capacity(n.min(PREALLOC_CAP));
5123 let mut prev = 0u64;
5124 for _ in 0..n {
5125 let bits = read_uvarint(buf, pos)? ^ prev;
5126 prev = bits;
5127 v.push(f64::from_bits(bits));
5128 }
5129 RuntimeValue::List(Rc::new(RefCell::new(ListRepr::Floats(v))))
5130 }
5131 T_BOOLS => {
5132 let n = read_uvarint(buf, pos)? as usize;
5133 let nbytes = n.div_ceil(8);
5134 let bits = buf.get(*pos..pos.checked_add(nbytes)?)?;
5135 *pos += nbytes;
5136 let mut v = Vec::with_capacity(n.min(PREALLOC_CAP));
5137 for i in 0..n {
5138 v.push((bits[i / 8] >> (i % 8)) & 1 == 1);
5139 }
5140 RuntimeValue::List(Rc::new(RefCell::new(ListRepr::Bools(v))))
5141 }
5142 T_BOOLS_PERIODIC => {
5144 let p = bounded_count(read_uvarint(buf, pos)?)?;
5145 if p == 0 {
5146 return None;
5147 }
5148 let n = bounded_count(read_uvarint(buf, pos)?)?;
5149 let block_bytes = p.div_ceil(8);
5150 let raw = buf.get(*pos..pos.checked_add(block_bytes)?)?;
5151 *pos += block_bytes;
5152 let block: Vec<bool> = (0..p).map(|i| (raw[i / 8] >> (i % 8)) & 1 == 1).collect();
5153 let mut v = Vec::with_capacity(n.min(PREALLOC_CAP));
5154 for i in 0..n {
5155 v.push(block[i % p]);
5156 }
5157 RuntimeValue::List(Rc::new(RefCell::new(ListRepr::Bools(v))))
5158 }
5159 T_BOOLS_RLE => {
5161 let n = bounded_count(read_uvarint(buf, pos)?)?;
5162 let first = *buf.get(*pos)? != 0;
5163 *pos += 1;
5164 let nruns = bounded_count(read_uvarint(buf, pos)?)?;
5165 let mut v = Vec::with_capacity(n.min(PREALLOC_CAP));
5166 let mut cur = first;
5167 for _ in 0..nruns {
5168 let runlen = bounded_count(read_uvarint(buf, pos)?)?;
5169 if v.len().checked_add(runlen)? > n {
5171 return None;
5172 }
5173 v.resize(v.len() + runlen, cur);
5174 cur = !cur;
5175 }
5176 if v.len() != n {
5177 return None;
5178 }
5179 RuntimeValue::List(Rc::new(RefCell::new(ListRepr::Bools(v))))
5180 }
5181 T_STRINGS => {
5182 let n = read_uvarint(buf, pos)? as usize;
5183 let mut ends = Vec::with_capacity(n.min(PREALLOC_CAP));
5184 let mut total: u64 = 0;
5185 for _ in 0..n {
5186 total = total.checked_add(read_uvarint(buf, pos)?)?;
5187 ends.push(u32::try_from(total).ok()?);
5188 }
5189 let total = usize::try_from(total).ok()?;
5190 let raw = buf.get(*pos..pos.checked_add(total)?)?;
5191 *pos += total;
5192 if std::str::from_utf8(raw).is_err() {
5196 return None;
5197 }
5198 RuntimeValue::List(Rc::new(RefCell::new(ListRepr::strings(raw.to_vec(), ends))))
5199 }
5200 T_STRINGS_TEMPLATE => {
5202 let plen = bounded_count(read_uvarint(buf, pos)?)?;
5203 let prefix = buf.get(*pos..pos.checked_add(plen)?)?.to_vec();
5204 *pos += plen;
5205 let slen = bounded_count(read_uvarint(buf, pos)?)?;
5206 let suffix = buf.get(*pos..pos.checked_add(slen)?)?.to_vec();
5207 *pos += slen;
5208 let base = unzigzag(read_uvarint(buf, pos)?);
5209 let stride = unzigzag(read_uvarint(buf, pos)?);
5210 let n = bounded_count(read_uvarint(buf, pos)?)?;
5211 if std::str::from_utf8(&prefix).is_err() || std::str::from_utf8(&suffix).is_err() {
5213 return None;
5214 }
5215 let mut data = Vec::new();
5216 let mut ends = Vec::with_capacity(n.min(PREALLOC_CAP));
5217 for i in 0..n {
5218 let num = base.wrapping_add((i as i64).wrapping_mul(stride));
5219 data.extend_from_slice(&prefix);
5220 data.extend_from_slice(num.to_string().as_bytes());
5221 data.extend_from_slice(&suffix);
5222 ends.push(u32::try_from(data.len()).ok()?);
5223 }
5224 RuntimeValue::List(Rc::new(RefCell::new(ListRepr::strings(data, ends))))
5225 }
5226 T_STRINGS_FRONT => {
5228 let n = bounded_count(read_uvarint(buf, pos)?)?;
5229 let mut data: Vec<u8> = Vec::new();
5230 let mut ends = Vec::with_capacity(n.min(PREALLOC_CAP));
5231 let mut prev: Vec<u8> = Vec::new();
5232 for _ in 0..n {
5233 let common = bounded_count(read_uvarint(buf, pos)?)?;
5234 let suffix_len = bounded_count(read_uvarint(buf, pos)?)?;
5235 if common > prev.len() {
5237 return None;
5238 }
5239 let suffix = buf.get(*pos..pos.checked_add(suffix_len)?)?;
5240 *pos += suffix_len;
5241 let mut s = Vec::with_capacity(common.checked_add(suffix_len)?);
5242 s.extend_from_slice(&prev[..common]);
5243 s.extend_from_slice(suffix);
5244 data.extend_from_slice(&s);
5245 ends.push(u32::try_from(data.len()).ok()?);
5246 prev = s;
5247 }
5248 if std::str::from_utf8(&data).is_err() {
5251 return None;
5252 }
5253 RuntimeValue::List(Rc::new(RefCell::new(ListRepr::strings(data, ends))))
5254 }
5255 T_STRINGS_AFFIX => {
5257 let plen = bounded_count(read_uvarint(buf, pos)?)?;
5258 let prefix = buf.get(*pos..pos.checked_add(plen)?)?.to_vec();
5259 *pos += plen;
5260 let slen = bounded_count(read_uvarint(buf, pos)?)?;
5261 let suffix = buf.get(*pos..pos.checked_add(slen)?)?.to_vec();
5262 *pos += slen;
5263 let n = bounded_count(read_uvarint(buf, pos)?)?;
5264 let mut data: Vec<u8> = Vec::new();
5265 let mut ends = Vec::with_capacity(n.min(PREALLOC_CAP));
5266 for _ in 0..n {
5267 let mid_len = bounded_count(read_uvarint(buf, pos)?)?;
5268 let mid = buf.get(*pos..pos.checked_add(mid_len)?)?;
5269 *pos += mid_len;
5270 data.extend_from_slice(&prefix);
5271 data.extend_from_slice(mid);
5272 data.extend_from_slice(&suffix);
5273 ends.push(u32::try_from(data.len()).ok()?);
5274 }
5275 if std::str::from_utf8(&data).is_err() {
5277 return None;
5278 }
5279 RuntimeValue::List(Rc::new(RefCell::new(ListRepr::strings(data, ends))))
5280 }
5281 T_STRINGS_DICT => {
5284 let d = read_uvarint(buf, pos)? as usize;
5285 let mut dict: Vec<&[u8]> = Vec::with_capacity(d.min(PREALLOC_CAP));
5286 for _ in 0..d {
5287 let len = read_uvarint(buf, pos)? as usize;
5288 let s = buf.get(*pos..pos.checked_add(len)?)?;
5289 if std::str::from_utf8(s).is_err() {
5290 return None;
5291 }
5292 dict.push(s);
5293 *pos += len;
5294 }
5295 let n = read_uvarint(buf, pos)? as usize;
5296 let iw = *buf.get(*pos)?;
5297 *pos += 1;
5298 if iw > 64 {
5299 return None;
5300 }
5301 let mut out_data: Vec<u8> = Vec::new();
5302 let mut out_ends: Vec<u32> = Vec::with_capacity(n.min(PREALLOC_CAP));
5303 let mut push = |s: &[u8], out_data: &mut Vec<u8>, out_ends: &mut Vec<u32>| {
5304 out_data.extend_from_slice(s);
5305 out_ends.push(out_data.len() as u32);
5306 };
5307 if iw == 0 {
5308 if n > 0 {
5309 let s = *dict.first()?;
5310 for _ in 0..n {
5311 push(s, &mut out_data, &mut out_ends);
5312 }
5313 }
5314 } else {
5315 let nbytes = n.checked_mul(iw as usize)?.div_ceil(8);
5316 let bytes = buf.get(*pos..pos.checked_add(nbytes)?)?;
5317 *pos += nbytes;
5318 for ix in bitunpack(bytes, n, iw)? {
5319 push(*dict.get(ix as usize)?, &mut out_data, &mut out_ends);
5320 }
5321 }
5322 RuntimeValue::List(Rc::new(RefCell::new(ListRepr::strings(out_data, out_ends))))
5323 }
5324 T_TUPLE => RuntimeValue::Tuple(Rc::new(read_seq(buf, pos)?)),
5325 T_SET => RuntimeValue::Set(Rc::new(RefCell::new(read_seq(buf, pos)?))),
5326 T_SET_INTS => {
5327 let ints = match native_decode(buf, pos)? {
5330 RuntimeValue::List(l) => l.borrow().to_values(),
5331 _ => return None,
5332 };
5333 RuntimeValue::Set(Rc::new(RefCell::new(ints)))
5334 }
5335 T_SET_STRINGS => {
5336 let n = read_uvarint(buf, pos)? as usize;
5338 let mut items = Vec::with_capacity(n);
5339 let mut prev = String::new();
5340 for _ in 0..n {
5341 let common = read_uvarint(buf, pos)? as usize;
5342 if common > prev.len() || !prev.is_char_boundary(common) {
5343 return None;
5344 }
5345 let suffix = read_str(buf, pos)?;
5346 let s = format!("{}{}", &prev[..common], suffix);
5347 items.push(RuntimeValue::Text(Rc::new(s.clone())));
5348 prev = s;
5349 }
5350 RuntimeValue::Set(Rc::new(RefCell::new(items)))
5351 }
5352 T_MAP => {
5353 let n = read_uvarint(buf, pos)?;
5354 let mut m = MapStorage::default();
5355 for _ in 0..n {
5356 let k = native_decode(buf, pos)?;
5357 let v = native_decode(buf, pos)?;
5358 m.insert(k, v);
5359 }
5360 RuntimeValue::Map(Rc::new(RefCell::new(m)))
5361 }
5362 T_MAP_INTKEY => {
5363 let keys = match native_decode(buf, pos)? {
5366 RuntimeValue::List(l) => l.borrow().to_values(),
5367 _ => return None,
5368 };
5369 let kind = *buf.get(*pos)?;
5370 *pos += 1;
5371 let vals: Vec<RuntimeValue> = match kind {
5372 1 => match native_decode(buf, pos)? {
5373 RuntimeValue::List(l) => l.borrow().to_values(),
5374 _ => return None,
5375 },
5376 2 => {
5377 let n = read_uvarint(buf, pos)? as usize;
5380 let mut vs = Vec::with_capacity(n.min(keys.len().saturating_add(1)));
5381 let mut prev = String::new();
5382 for _ in 0..n {
5383 let common = read_uvarint(buf, pos)? as usize;
5384 if common > prev.len() || !prev.is_char_boundary(common) {
5385 return None;
5386 }
5387 let suffix = read_str(buf, pos)?;
5388 let s = format!("{}{}", &prev[..common], suffix);
5389 vs.push(RuntimeValue::Text(Rc::new(s.clone())));
5390 prev = s;
5391 }
5392 vs
5393 }
5394 3 => match native_decode(buf, pos)? {
5395 RuntimeValue::List(l) => l.borrow().to_values(),
5397 _ => return None,
5398 },
5399 0 => {
5400 let n = read_uvarint(buf, pos)? as usize;
5401 let mut vs = Vec::with_capacity(n.min(keys.len().saturating_add(1)));
5402 for _ in 0..n {
5403 vs.push(native_decode(buf, pos)?);
5404 }
5405 vs
5406 }
5407 _ => return None,
5408 };
5409 if keys.len() != vals.len() {
5410 return None;
5411 }
5412 let mut m = MapStorage::default();
5413 for (k, v) in keys.into_iter().zip(vals.into_iter()) {
5414 m.insert(k, v);
5415 }
5416 RuntimeValue::Map(Rc::new(RefCell::new(m)))
5417 }
5418 T_STRUCT => {
5419 let type_name = read_str(buf, pos)?;
5420 let n = read_uvarint(buf, pos)?;
5421 let mut fields = std::collections::HashMap::with_capacity((n as usize).min(PREALLOC_CAP));
5422 for _ in 0..n {
5423 let name = read_str(buf, pos)?;
5424 let val = native_decode(buf, pos)?;
5425 fields.insert(name, val);
5426 }
5427 RuntimeValue::Struct(Box::new(StructValue { type_name, fields }))
5428 }
5429 T_STRUCT_DEF => {
5432 let id = read_uvarint(buf, pos)? as u32;
5433 let (type_name, field_names) = read_struct_schema(buf, pos)?;
5434 if !schema_recv_register_seq(id, &type_name, &field_names) {
5435 return None; }
5437 decode_struct_values(buf, pos, type_name, field_names)?
5438 }
5439 T_STRUCT_REF => {
5442 let id = read_uvarint(buf, pos)? as u32;
5443 let (type_name, field_names) = schema_recv_lookup_seq(id)?;
5444 decode_struct_values(buf, pos, type_name, field_names)?
5445 }
5446 T_STRUCT_CDEF => {
5450 let (type_name, field_names) = read_struct_schema(buf, pos)?;
5451 if !schema_recv_register_ca(&type_name, &field_names) {
5452 return None; }
5454 decode_struct_values(buf, pos, type_name, field_names)?
5455 }
5456 T_STRUCT_CREF => {
5459 let raw = buf.get(*pos..pos.checked_add(8)?)?;
5460 let fp = u64::from_le_bytes(raw.try_into().ok()?);
5461 *pos += 8;
5462 let (type_name, field_names) = schema_recv_lookup_ca(fp)?;
5463 decode_struct_values(buf, pos, type_name, field_names)?
5464 }
5465 T_STRUCT_TID => {
5468 let id = read_uvarint(buf, pos)? as u32;
5469 let (type_name, field_names) = type_registry_schema(id)?;
5470 decode_struct_values(buf, pos, type_name, field_names)?
5471 }
5472 T_STRUCT_VIEW => {
5475 let type_name = read_str(buf, pos)?;
5476 let n = read_uvarint(buf, pos)? as usize;
5477 let mut field_names = Vec::with_capacity(n.min(PREALLOC_CAP));
5478 for _ in 0..n {
5479 field_names.push(read_str(buf, pos)?);
5480 }
5481 *pos = pos.checked_add(n.checked_mul(4)?)?; if *pos > buf.len() {
5483 return None;
5484 }
5485 decode_struct_values(buf, pos, type_name, field_names)?
5486 }
5487 T_STRUCTS_VIEW => {
5491 let type_name = read_str(buf, pos)?;
5492 let f = read_uvarint(buf, pos)? as usize;
5493 let mut field_names = Vec::with_capacity(f.min(PREALLOC_CAP));
5494 for _ in 0..f {
5495 field_names.push(read_str(buf, pos)?);
5496 }
5497 let n = read_uvarint(buf, pos)? as usize;
5498 *pos = pos.checked_add(n.checked_mul(4)?)?; if *pos > buf.len() {
5500 return None;
5501 }
5502 let mut rows = Vec::with_capacity(n.min(PREALLOC_CAP));
5503 for _ in 0..n {
5504 *pos = pos.checked_add(f.checked_mul(4)?)?; if *pos > buf.len() {
5506 return None;
5507 }
5508 rows.push(decode_struct_values(buf, pos, type_name.clone(), field_names.clone())?);
5509 }
5510 RuntimeValue::List(Rc::new(RefCell::new(ListRepr::from_values(rows))))
5511 }
5512 T_STRUCTS_FVIEW => {
5515 let type_name = read_str(buf, pos)?;
5516 let f = read_uvarint(buf, pos)? as usize;
5517 let mut field_names = Vec::with_capacity(f.min(PREALLOC_CAP));
5518 for _ in 0..f {
5519 field_names.push(read_str(buf, pos)?);
5520 }
5521 let kinds = buf.get(*pos..pos.checked_add(f)?)?.to_vec();
5522 *pos += f;
5523 let n = read_uvarint(buf, pos)? as usize;
5524 let (offsets, stride) = fview_layout(&kinds);
5525 let rows_start = *pos;
5526 let rows_len = n.checked_mul(stride)?;
5527 let rows_bytes = buf.get(rows_start..rows_start.checked_add(rows_len)?)?;
5528 *pos = rows_start.checked_add(rows_len)?;
5529 let blob_len = read_uvarint(buf, pos)? as usize;
5530 let blob = buf.get(*pos..pos.checked_add(blob_len)?)?;
5531 *pos = pos.checked_add(blob_len)?;
5532 let mut columns: Vec<ListRepr> = Vec::with_capacity(f);
5536 for j in 0..f {
5537 let off = offsets[j];
5538 let col = match kinds[j] {
5539 FK_INT => {
5540 let mut v = Vec::with_capacity(n.min(PREALLOC_CAP));
5541 for r in 0..n {
5542 let base = r.checked_mul(stride)?.checked_add(off)?;
5543 v.push(i64::from_le_bytes(rows_bytes.get(base..base.checked_add(8)?)?.try_into().ok()?));
5544 }
5545 ListRepr::Ints(v)
5546 }
5547 FK_FLOAT => {
5548 let mut v = Vec::with_capacity(n.min(PREALLOC_CAP));
5549 for r in 0..n {
5550 let base = r.checked_mul(stride)?.checked_add(off)?;
5551 v.push(f64::from_le_bytes(rows_bytes.get(base..base.checked_add(8)?)?.try_into().ok()?));
5552 }
5553 ListRepr::Floats(v)
5554 }
5555 FK_BOOL => {
5556 let mut v = Vec::with_capacity(n.min(PREALLOC_CAP));
5557 for r in 0..n {
5558 let base = r.checked_mul(stride)?.checked_add(off)?;
5559 v.push(*rows_bytes.get(base)? != 0);
5560 }
5561 ListRepr::Bools(v)
5562 }
5563 FK_TEXT => {
5564 let mut data: Vec<u8> = Vec::new();
5565 let mut ends: Vec<u32> = Vec::with_capacity(n.min(PREALLOC_CAP));
5566 for r in 0..n {
5567 let base = r.checked_mul(stride)?.checked_add(off)?;
5568 let toff =
5569 u32::from_le_bytes(rows_bytes.get(base..base.checked_add(4)?)?.try_into().ok()?) as usize;
5570 let tlen = u32::from_le_bytes(
5571 rows_bytes.get(base.checked_add(4)?..base.checked_add(8)?)?.try_into().ok()?,
5572 ) as usize;
5573 data.extend_from_slice(blob.get(toff..toff.checked_add(tlen)?)?);
5574 ends.push(data.len() as u32);
5575 }
5576 ListRepr::strings(data, ends)
5577 }
5578 _ => return None,
5579 };
5580 columns.push(col);
5581 }
5582 RuntimeValue::List(Rc::new(RefCell::new(ListRepr::Structs { type_name, field_names, columns })))
5583 }
5584 T_INDUCTIVE => {
5585 let inductive_type = read_str(buf, pos)?;
5586 let constructor = read_str(buf, pos)?;
5587 let args = read_seq(buf, pos)?;
5588 RuntimeValue::Inductive(Box::new(InductiveValue { inductive_type, constructor, args }))
5589 }
5590 T_INDUCTIVE_TID => {
5593 let enum_id = read_uvarint(buf, pos)? as u32;
5594 let ctor_idx = read_uvarint(buf, pos)? as usize;
5595 let (inductive_type, ctors) = type_registry_enum_schema(enum_id)?;
5596 let constructor = ctors.get(ctor_idx)?.clone();
5597 let args = read_seq(buf, pos)?;
5598 RuntimeValue::Inductive(Box::new(InductiveValue { inductive_type, constructor, args }))
5599 }
5600 T_STRUCTS => {
5605 let (type_name, field_names) = read_struct_schema(buf, pos)?;
5606 decode_struct_columns(buf, pos, type_name, field_names)?
5607 }
5608 T_STRUCTS_TID => {
5611 let id = read_uvarint(buf, pos)? as u32;
5612 let (type_name, field_names) = type_registry_schema(id)?;
5613 decode_struct_columns(buf, pos, type_name, field_names)?
5614 }
5615 T_STRUCTS_DEF => {
5618 let id = read_uvarint(buf, pos)? as u32;
5619 let (type_name, field_names) = read_struct_schema(buf, pos)?;
5620 if !schema_recv_register_seq(id, &type_name, &field_names) {
5621 return None; }
5623 decode_struct_columns(buf, pos, type_name, field_names)?
5624 }
5625 T_STRUCTS_REF => {
5628 let id = read_uvarint(buf, pos)? as u32;
5629 let (type_name, field_names) = schema_recv_lookup_seq(id)?;
5630 decode_struct_columns(buf, pos, type_name, field_names)?
5631 }
5632 T_STRUCTS_CDEF => {
5636 let (type_name, field_names) = read_struct_schema(buf, pos)?;
5637 if !schema_recv_register_ca(&type_name, &field_names) {
5638 return None; }
5640 decode_struct_columns(buf, pos, type_name, field_names)?
5641 }
5642 T_STRUCTS_CREF => {
5645 let raw = buf.get(*pos..pos.checked_add(8)?)?;
5646 let fp = u64::from_le_bytes(raw.try_into().ok()?);
5647 *pos += 8;
5648 let (type_name, field_names) = schema_recv_lookup_ca(fp)?;
5649 decode_struct_columns(buf, pos, type_name, field_names)?
5650 }
5651 T_INDUCTIVES => {
5656 let inductive_type = read_str(buf, pos)?;
5657 let d = read_uvarint(buf, pos)? as usize;
5658 let mut ctor_dict = Vec::with_capacity(d.min(PREALLOC_CAP));
5659 let mut arities = Vec::with_capacity(d.min(PREALLOC_CAP));
5660 for _ in 0..d {
5661 ctor_dict.push(read_str(buf, pos)?);
5662 arities.push(read_uvarint(buf, pos)? as usize);
5663 }
5664 let idx = match native_decode(buf, pos)? {
5666 RuntimeValue::List(l) => Rc::try_unwrap(l).map(RefCell::into_inner).unwrap_or_else(|rc| rc.borrow().clone()),
5667 _ => return None,
5668 };
5669 let mut ctors: Vec<u32> = Vec::with_capacity(idx.len().min(PREALLOC_CAP));
5670 for v in idx.to_values() {
5671 match v {
5672 RuntimeValue::Int(i) if i >= 0 && (i as usize) < d => ctors.push(i as u32),
5673 _ => return None,
5674 }
5675 }
5676 let mut arg_cols: Vec<Vec<ListRepr>> = Vec::with_capacity(d.min(PREALLOC_CAP));
5678 for &arity in &arities {
5679 let mut cols = Vec::with_capacity(arity.min(PREALLOC_CAP));
5680 for _ in 0..arity {
5681 let col = match native_decode(buf, pos)? {
5682 RuntimeValue::List(l) => Rc::try_unwrap(l).map(RefCell::into_inner).unwrap_or_else(|rc| rc.borrow().clone()),
5683 _ => return None,
5684 };
5685 cols.push(col);
5686 }
5687 arg_cols.push(cols);
5688 }
5689 let mut counts = vec![0u32; d];
5691 let mut ranks = Vec::with_capacity(ctors.len());
5692 for &c in &ctors {
5693 ranks.push(counts[c as usize]);
5694 counts[c as usize] += 1;
5695 }
5696 for c in 0..d {
5697 if arg_cols[c].iter().any(|col| col.len() != counts[c] as usize) {
5698 return None; }
5700 }
5701 RuntimeValue::List(Rc::new(RefCell::new(ListRepr::Inductives {
5702 inductive_type,
5703 ctor_dict,
5704 ctors,
5705 ranks,
5706 arg_cols,
5707 })))
5708 }
5709 _ => return None,
5710 })
5711}
5712
5713fn read_seq(buf: &[u8], pos: &mut usize) -> Option<Vec<RuntimeValue>> {
5714 let n = bounded_count(read_uvarint(buf, pos)?)?;
5715 let mut v = Vec::with_capacity(n.min(PREALLOC_CAP));
5716 for _ in 0..n {
5717 v.push(native_decode(buf, pos)?);
5718 }
5719 Some(v)
5720}
5721
5722fn read_struct_schema(buf: &[u8], pos: &mut usize) -> Option<(String, Vec<String>)> {
5724 let type_name = read_str(buf, pos)?;
5725 let k = read_uvarint(buf, pos)? as usize;
5726 let mut field_names = Vec::with_capacity(k.min(PREALLOC_CAP));
5727 for _ in 0..k {
5728 field_names.push(read_str(buf, pos)?);
5729 }
5730 Some((type_name, field_names))
5731}
5732
5733fn decode_struct_values(
5736 buf: &[u8],
5737 pos: &mut usize,
5738 type_name: String,
5739 field_names: Vec<String>,
5740) -> Option<RuntimeValue> {
5741 let mut fields = std::collections::HashMap::with_capacity(field_names.len().min(PREALLOC_CAP));
5742 for name in field_names {
5743 let val = native_decode(buf, pos)?;
5744 fields.insert(name, val);
5745 }
5746 Some(RuntimeValue::Struct(Box::new(StructValue { type_name, fields })))
5747}
5748
5749fn decode_struct_columns(
5754 buf: &[u8],
5755 pos: &mut usize,
5756 type_name: String,
5757 field_names: Vec<String>,
5758) -> Option<RuntimeValue> {
5759 let k = field_names.len();
5760 let n = read_uvarint(buf, pos)? as usize;
5761 let mut columns: Vec<ListRepr> = Vec::with_capacity(k.min(PREALLOC_CAP));
5762 for _ in 0..k {
5763 let col = match native_decode(buf, pos)? {
5767 RuntimeValue::List(l) => Rc::try_unwrap(l).map(RefCell::into_inner).unwrap_or_else(|rc| rc.borrow().clone()),
5768 _ => return None,
5769 };
5770 if col.len() != n {
5771 return None; }
5773 columns.push(col);
5774 }
5775 Some(if columns.is_empty() {
5776 let rows = (0..n)
5777 .map(|_| {
5778 RuntimeValue::Struct(Box::new(StructValue {
5779 type_name: type_name.clone(),
5780 fields: std::collections::HashMap::new(),
5781 }))
5782 })
5783 .collect();
5784 RuntimeValue::List(Rc::new(RefCell::new(ListRepr::Boxed(rows))))
5785 } else {
5786 RuntimeValue::List(Rc::new(RefCell::new(ListRepr::Structs { type_name, field_names, columns })))
5787 })
5788}
5789
5790fn header(codec: WireCodec, integrity: WireIntegrity, compression: WireCompression) -> u8 {
5791 let c = if matches!(codec, WireCodec::Json) { H_JSON } else { 0 };
5792 let i = if matches!(integrity, WireIntegrity::Checked) { H_CHECKED } else { 0 };
5793 let z = if compression == WireCompression::None { 0 } else { H_COMPRESSED | (compression_id(compression) << 2) };
5794 c | i | z
5795}
5796
5797fn frame(codec: WireCodec, integrity: WireIntegrity, compression: WireCompression, body: Vec<u8>) -> Vec<u8> {
5800 let h = header(codec, integrity, compression);
5801 match integrity {
5802 WireIntegrity::Raw => {
5803 let mut out = Vec::with_capacity(body.len() + 1);
5804 out.push(h);
5805 out.extend_from_slice(&body);
5806 out
5807 }
5808 WireIntegrity::Checked => {
5809 let mut out = Vec::with_capacity(body.len() + 9);
5810 out.push(h);
5811 out.extend_from_slice(&fnv1a_64(&body).to_le_bytes());
5812 out.extend_from_slice(&body);
5813 out
5814 }
5815 }
5816}
5817
5818fn unframe_with(bytes: &[u8], verify: bool) -> Option<(WireCodec, WireCompression, &[u8])> {
5827 let (&h, rest) = bytes.split_first()?;
5828 if h & !H_KNOWN != 0 {
5829 return None; }
5831 let codec = if h & H_JSON != 0 { WireCodec::Json } else { WireCodec::Native };
5832 let compression = if h & H_COMPRESSED == 0 {
5833 WireCompression::None
5834 } else {
5835 match (h & H_CODEC) >> 2 {
5836 0 => WireCompression::Deflate,
5837 1 => WireCompression::Lz4,
5838 2 => WireCompression::Zstd,
5839 _ => return None, }
5841 };
5842 let body = if h & H_CHECKED != 0 {
5843 if rest.len() < 8 {
5844 return None;
5845 }
5846 let (sum, body) = rest.split_at(8);
5847 if verify {
5848 let expected = u64::from_le_bytes(sum.try_into().ok()?);
5849 if fnv1a_64(body) != expected {
5850 return None;
5851 }
5852 }
5853 body
5854 } else {
5855 rest
5856 };
5857 Some((codec, compression, body))
5858}
5859
5860fn unframe(bytes: &[u8]) -> Option<(WireCodec, WireCompression, &[u8])> {
5862 unframe_with(bytes, true)
5863}
5864
5865fn fnv1a_64(bytes: &[u8]) -> u64 {
5869 let mut hash = 0xcbf2_9ce4_8422_2325u64;
5870 for &b in bytes {
5871 hash ^= b as u64;
5872 hash = hash.wrapping_mul(0x0000_0100_0000_01b3);
5873 }
5874 hash
5875}
5876
5877pub(crate) fn default_integrity() -> WireIntegrity {
5880 static MODE: std::sync::OnceLock<WireIntegrity> = std::sync::OnceLock::new();
5881 *MODE.get_or_init(|| match std::env::var("LOGOS_WIRE").ok().as_deref() {
5882 Some("raw") => WireIntegrity::Raw,
5883 _ => WireIntegrity::Checked,
5884 })
5885}
5886
5887thread_local! {
5888 static INTEGRITY_OVERRIDE: std::cell::Cell<Option<WireIntegrity>> = const { std::cell::Cell::new(None) };
5889}
5890
5891pub fn with_integrity<T>(integrity: WireIntegrity, f: impl FnOnce() -> T) -> T {
5896 let prev = INTEGRITY_OVERRIDE.with(|c| c.replace(Some(integrity)));
5897 let out = f();
5898 INTEGRITY_OVERRIDE.with(|c| c.set(prev));
5899 out
5900}
5901
5902fn current_integrity() -> WireIntegrity {
5905 INTEGRITY_OVERRIDE.with(std::cell::Cell::get).unwrap_or_else(default_integrity)
5906}
5907
5908fn wire_options() -> impl bincode::Options {
5912 bincode::DefaultOptions::new()
5913}
5914
5915fn canon_bytes(w: &WireValue) -> Vec<u8> {
5918 use bincode::Options;
5919 wire_options().serialize(w).unwrap_or_default()
5920}
5921
5922#[cfg(test)]
5923mod tests {
5924 use super::*;
5925 use crate::interpreter::ClosureValue;
5926 use std::collections::HashMap;
5927
5928 fn ints_list(v: Vec<i64>) -> RuntimeValue {
5933 RuntimeValue::List(Rc::new(RefCell::new(ListRepr::Ints(v))))
5934 }
5935
5936 #[test]
5937 fn describe_columns_names_the_numeric_dials() {
5938 let ints = ints_list((0i64..64).map(|i| 3 + i * 7).collect());
5939 let enc = |num: WireNumerics| {
5940 with_structure(WireStructure::Off, || {
5941 with_numerics(num, || {
5942 message_to_wire_with("", &ints, WireCodec::Native, WireIntegrity::Raw).unwrap()
5943 })
5944 })
5945 };
5946 assert_eq!(describe_columns(&enc(WireNumerics::Varint)), vec!["varint"]);
5947 assert_eq!(describe_columns(&enc(WireNumerics::Fixed)), vec!["fixed (memcpy)"]);
5948 assert_eq!(describe_columns(&enc(WireNumerics::GroupVarint)), vec!["group-varint"]);
5949 }
5950
5951 #[test]
5952 fn describe_columns_names_the_affine_structure() {
5953 let ints = ints_list((0i64..64).map(|i| 5 + i * 3).collect());
5954 let bytes = with_structure(WireStructure::Affine, || {
5955 with_numerics(WireNumerics::Varint, || {
5956 message_to_wire_with("", &ints, WireCodec::Native, WireIntegrity::Raw).unwrap()
5957 })
5958 });
5959 assert_eq!(describe_columns(&bytes), vec!["affine (base,stride,n)"]);
5960 }
5961
5962 #[test]
5963 fn describe_columns_names_the_float_dials() {
5964 let floats = floats_list((0..256).map(|i| 20.0 + i as f64 * 0.01).collect());
5966 let enc = |fl: WireFloats| {
5967 with_structure(WireStructure::Off, || {
5968 with_floats(fl, || {
5969 message_to_wire_with("", &floats, WireCodec::Native, WireIntegrity::Raw).unwrap()
5970 })
5971 })
5972 };
5973 assert_eq!(describe_columns(&enc(WireFloats::Memcpy)), vec!["memcpy floats"]);
5974 assert_eq!(describe_columns(&enc(WireFloats::XorDelta)), vec!["xor-delta floats"]);
5975 }
5976
5977 #[test]
5978 fn describe_columns_names_strings_and_bools() {
5979 let strings = RuntimeValue::List(Rc::new(RefCell::new(ListRepr::from_values(
5980 (0..24).map(|i| RuntimeValue::Text(Rc::new(format!("host-{i}-{}", i * 31 % 7)))).collect(),
5981 ))));
5982 let bools = RuntimeValue::List(Rc::new(RefCell::new(ListRepr::from_values(
5983 (0..40).map(|i| RuntimeValue::Bool(i * 5 % 3 == 0)).collect(),
5984 ))));
5985 let enc = |rv: &RuntimeValue| {
5986 with_structure(WireStructure::Off, || {
5987 message_to_wire_with("", rv, WireCodec::Native, WireIntegrity::Raw).unwrap()
5988 })
5989 };
5990 assert_eq!(describe_columns(&enc(&strings)), vec!["flat strings"]);
5991 assert_eq!(describe_columns(&enc(&bools)), vec!["bit-packed bools"]);
5992 }
5993
5994 #[test]
5995 fn describe_columns_names_each_record_field() {
5996 let mut rows = Vec::new();
5997 for i in 0..32i64 {
5998 let mut f = HashMap::new();
5999 f.insert("id".to_string(), RuntimeValue::Int(i * 3 + 1));
6000 f.insert("name".to_string(), RuntimeValue::Text(Rc::new(format!("node-{i}"))));
6001 f.insert("active".to_string(), RuntimeValue::Bool(i % 2 == 0));
6002 rows.push(RuntimeValue::Struct(Box::new(StructValue { type_name: "Record".to_string(), fields: f })));
6003 }
6004 let rv = RuntimeValue::List(Rc::new(RefCell::new(ListRepr::from_values(rows))));
6005 let bytes = with_structure(WireStructure::Off, || {
6006 with_numerics(WireNumerics::Varint, || {
6007 message_to_wire_with("", &rv, WireCodec::Native, WireIntegrity::Raw).unwrap()
6008 })
6009 });
6010 let cols = describe_columns(&bytes);
6012 let got: std::collections::BTreeSet<&str> = cols.iter().map(String::as_str).collect();
6013 let want: std::collections::BTreeSet<&str> =
6014 ["active: bit-packed bools", "id: varint", "name: flat strings"].into_iter().collect();
6015 assert_eq!(got, want);
6016 }
6017
6018 #[test]
6019 fn column_tag_name_covers_the_structural_vocabulary() {
6020 for (tag, want) in [
6023 (T_INTS, "varint"),
6024 (T_INTS_FIXED, "fixed (memcpy)"),
6025 (T_INTS_GV, "group-varint"),
6026 (T_INTS_AFFINE, "affine (base,stride,n)"),
6027 (T_INTS_DELTA, "delta"),
6028 (T_INTS_DOD, "delta-of-delta"),
6029 (T_INTS_FOR, "FOR bit-pack"),
6030 (T_INTS_RLE, "run-length"),
6031 (T_INTS_DICT, "dictionary"),
6032 (T_FLOATS, "memcpy floats"),
6033 (T_FLOATS_XOR, "xor-delta floats"),
6034 (T_BOOLS, "bit-packed bools"),
6035 (T_STRINGS, "flat strings"),
6036 ] {
6037 assert_eq!(column_tag_name(tag), want, "tag {tag}");
6038 assert_ne!(column_tag_name(tag), "value", "tag {tag} must not be the generic fallback");
6039 }
6040 }
6041
6042 #[test]
6047 fn build_in_place_record_reads_back_zero_copy() {
6048 let ids: Vec<i64> = (0..1000).collect();
6052 let xs: Vec<f64> = (0..1000).map(|i| i as f64 * 0.5).collect();
6053 let bytes = build_columnar_record(
6054 "node",
6055 "Sensor",
6056 &[("id", WireColumn::Ints(&ids)), ("x", WireColumn::Floats(&xs))],
6057 );
6058 let view = view_message(&bytes).expect("the built record opens as a view");
6059 let id_slice = view.struct_field("id").expect("id field").as_i64_slice().expect("zero-copy i64");
6060 let x_slice = view.struct_field("x").expect("x field").as_f64_slice().expect("zero-copy f64");
6061 assert_eq!(id_slice, &ids[..], "id column round-trips bit-exact, zero-copy");
6062 assert_eq!(x_slice, &xs[..], "x column round-trips bit-exact, zero-copy");
6063 }
6064
6065 #[test]
6066 fn build_in_place_is_byte_identical_to_the_runtimevalue_path() {
6067 let a: Vec<i64> = vec![10, 20, 30, 40];
6071 let b: Vec<f64> = vec![1.5, 2.5, 3.5];
6072 let built = build_columnar_record(
6073 "p",
6074 "Rec",
6075 &[("alpha", WireColumn::Ints(&a)), ("beta", WireColumn::Floats(&b))],
6076 );
6077
6078 let mut fields = HashMap::new();
6079 fields.insert("alpha".to_string(), RuntimeValue::List(Rc::new(RefCell::new(ListRepr::Ints(a.clone())))));
6080 fields.insert("beta".to_string(), RuntimeValue::List(Rc::new(RefCell::new(ListRepr::Floats(b.clone())))));
6081 let sv = RuntimeValue::Struct(Box::new(StructValue { type_name: "Rec".to_string(), fields }));
6082 let canonical = with_struct_view(true, || {
6083 message_to_wire_with("p", &sv, WireCodec::Native, current_integrity()).unwrap()
6084 });
6085 assert_eq!(built, canonical, "build-in-place must equal the canonical struct-view encode byte-for-byte");
6086 }
6087
6088 #[test]
6089 fn build_in_place_record_full_decode_interop() {
6090 let a: Vec<i64> = vec![7, 8, 9];
6093 let bytes = build_columnar_record("p", "R", &[("c", WireColumn::Ints(&a))]);
6094 let (from, val) = message_from_wire(&bytes).expect("full decode");
6095 assert_eq!(from, "p");
6096 match val {
6097 RuntimeValue::Struct(s) => {
6098 assert_eq!(s.type_name, "R");
6099 match s.fields.get("c").unwrap() {
6100 RuntimeValue::List(l) => match &*l.borrow() {
6101 ListRepr::Ints(v) => assert_eq!(v, &a),
6102 other => panic!("expected Ints, got {other:?}"),
6103 },
6104 other => panic!("expected List, got {other:?}"),
6105 }
6106 }
6107 other => panic!("expected Struct, got {other:?}"),
6108 }
6109 }
6110
6111 #[test]
6112 #[ignore = "build-in-place encode-parity measurement — run with --ignored --nocapture"]
6113 fn build_in_place_encode_is_at_capnp_parity() {
6114 use std::time::Instant;
6120 const ITERS: usize = 4000;
6121 let cols: Vec<Vec<i64>> = (0..8).map(|c| (0..256).map(|i| (c * 256 + i) as i64).collect()).collect();
6122 let names: Vec<String> = (0..8).map(|c| format!("col{c}")).collect();
6123
6124 let mut fields_map = HashMap::new();
6126 for (n, c) in names.iter().zip(&cols) {
6127 fields_map.insert(n.clone(), RuntimeValue::List(Rc::new(RefCell::new(ListRepr::Ints(c.clone())))));
6128 }
6129 let sv = RuntimeValue::Struct(Box::new(StructValue { type_name: "Batch".to_string(), fields: fields_map }));
6130
6131 let t = Instant::now();
6132 for _ in 0..ITERS {
6133 let fields: Vec<(&str, WireColumn)> =
6134 names.iter().zip(&cols).map(|(n, c)| (n.as_str(), WireColumn::Ints(c))).collect();
6135 std::hint::black_box(build_columnar_record("p", "Batch", &fields));
6136 }
6137 let in_place = t.elapsed();
6138
6139 let t = Instant::now();
6140 for _ in 0..ITERS {
6141 let bytes = with_struct_view(true, || {
6142 message_to_wire_with("p", &sv, WireCodec::Native, current_integrity()).unwrap()
6143 });
6144 std::hint::black_box(bytes);
6145 }
6146 let serialize_existing = t.elapsed();
6147
6148 eprintln!(
6149 "encode 8×256 i64 record: build-in-place={in_place:?} serialize-existing={serialize_existing:?} ratio={:.2}x",
6150 serialize_existing.as_secs_f64() / in_place.as_secs_f64().max(f64::MIN_POSITIVE)
6151 );
6152 assert!(
6155 in_place.as_secs_f64() <= serialize_existing.as_secs_f64() * 1.5,
6156 "build-in-place must be at parity with the existing column encode: in_place={in_place:?} existing={serialize_existing:?}"
6157 );
6158 }
6159
6160 #[test]
6161 fn columnar_record_is_position_independent_mmap_and_ipc_ready() {
6162 let ids: Vec<i64> = (0..4096).collect();
6168 let xs: Vec<f64> = (0..4096).map(|i| i as f64 * 1.25).collect();
6169 let msg = build_columnar_record(
6170 "p",
6171 "Batch",
6172 &[("id", WireColumn::Ints(&ids)), ("x", WireColumn::Floats(&xs))],
6173 );
6174
6175 for &shift in &[0usize, 8, 16, 4096, 65536] {
6179 let mut arena = vec![0u8; shift];
6180 arena.extend_from_slice(&msg);
6181 let relocated = &arena[shift..]; let view = view_message(relocated).expect("position-independent open at any base");
6183 let id_slice = view.struct_field("id").unwrap().as_i64_slice().expect("zero-copy at aligned base");
6184 let x_slice = view.struct_field("x").unwrap().as_f64_slice().expect("zero-copy at aligned base");
6185 assert_eq!(id_slice, &ids[..], "id column read in place at base+{shift}");
6186 assert_eq!(x_slice, &xs[..], "x column read in place at base+{shift}");
6187 }
6188
6189 let mut arena = vec![0u8; 3];
6193 arena.extend_from_slice(&msg);
6194 let view = view_message(&arena[3..]).expect("opens at an unaligned base too");
6195 let (_, val) = message_from_wire(&arena[3..]).expect("full decode at unaligned base");
6196 match val {
6197 RuntimeValue::Struct(s) => match s.fields.get("id").unwrap() {
6198 RuntimeValue::List(l) => match &*l.borrow() {
6199 ListRepr::Ints(v) => assert_eq!(v, &ids, "correct at an unaligned base via the copy path"),
6200 o => panic!("expected Ints, got {o:?}"),
6201 },
6202 o => panic!("expected List, got {o:?}"),
6203 },
6204 o => panic!("expected Struct, got {o:?}"),
6205 }
6206 assert!(view.struct_field("id").is_some(), "field still locatable at an unaligned base");
6209 }
6210
6211 #[test]
6212 fn columnar_record_mmaps_a_column_zero_copy_from_disk() {
6213 use std::io::Write;
6219 let ids: Vec<i64> = (0..50_000).collect();
6220 let xs: Vec<f64> = (0..50_000).map(|i| (i as f64).sqrt()).collect();
6221 let msg = build_columnar_record(
6222 "p",
6223 "Telemetry",
6224 &[("id", WireColumn::Ints(&ids)), ("x", WireColumn::Floats(&xs))],
6225 );
6226
6227 let mut tmp = tempfile::NamedTempFile::new().expect("temp file");
6228 tmp.write_all(&msg).expect("write the wire message to disk");
6229 tmp.flush().expect("flush");
6230 let file = tmp.reopen().expect("reopen for mapping");
6231 let mmap = unsafe { memmap2::Mmap::map(&file).expect("mmap the message file") };
6233
6234 let view = view_message(&mmap[..]).expect("the mmap'd message opens in place");
6235 let id_slice = view.struct_field("id").unwrap().as_i64_slice().expect("zero-copy i64 from mmap");
6236 let x_slice = view.struct_field("x").unwrap().as_f64_slice().expect("zero-copy f64 from mmap");
6237 assert_eq!(id_slice, &ids[..], "id column read zero-copy directly from the mmap");
6239 assert_eq!(x_slice, &xs[..], "x column read zero-copy directly from the mmap");
6240 let map_base = mmap.as_ptr() as usize;
6242 let slice_base = id_slice.as_ptr() as usize;
6243 assert!(
6244 slice_base >= map_base && slice_base < map_base + mmap.len(),
6245 "the i64 slice must alias the mapped pages, not a copy"
6246 );
6247 }
6248
6249 #[test]
6250 fn wireview_decode_and_schema_read_a_record_list_in_place() {
6251 let mk = |id: i64, x: f64| {
6255 let mut f = HashMap::new();
6256 f.insert("id".to_string(), RuntimeValue::Int(id));
6257 f.insert("x".to_string(), RuntimeValue::Float(x));
6258 RuntimeValue::Struct(Box::new(StructValue { type_name: "Rec".to_string(), fields: f }))
6259 };
6260 let rows = vec![mk(10, 1.5), mk(20, 2.5), mk(30, 3.5)];
6261 let list = RuntimeValue::List(Rc::new(RefCell::new(ListRepr::from_values(rows))));
6262 let bytes = with_struct_view(true, || {
6263 message_to_wire_with("p", &list, WireCodec::Native, WireIntegrity::Raw).unwrap()
6264 });
6265 let view = view_message(&bytes).expect("record list opens as a view");
6266
6267 let (ty, fields, n) = view.structs_schema().expect("record-list schema in place");
6268 assert_eq!(ty, "Rec");
6269 assert_eq!(fields, vec!["id".to_string(), "x".to_string()], "sorted field schema");
6270 assert_eq!(n, 3, "row count from the header, no rows decoded");
6271
6272 assert_eq!(view.structs_row_field(1, "id").unwrap().decode(), Some(RuntimeValue::Int(20)));
6273 assert_eq!(view.structs_row_field(2, "x").unwrap().decode(), Some(RuntimeValue::Float(3.5)));
6274 assert_eq!(view.structs_row_field(0, "id").unwrap().decode(), Some(RuntimeValue::Int(10)));
6275 assert!(view.structs_row_field(3, "id").is_none(), "out-of-range row is None");
6276 assert!(view.structs_row_field(0, "nope").is_none(), "missing field is None");
6277 }
6278
6279 #[test]
6280 fn lazy_wirestructs_reads_records_without_eager_decode() {
6281 use crate::interpreter::{ListRepr, StructValue};
6285 let mk = |id: i64, x: f64, tag: &str| {
6286 let mut f = HashMap::new();
6287 f.insert("id".to_string(), RuntimeValue::Int(id));
6288 f.insert("x".to_string(), RuntimeValue::Float(x));
6289 f.insert("tag".to_string(), RuntimeValue::Text(Rc::new(tag.to_string())));
6290 RuntimeValue::Struct(Box::new(StructValue { type_name: "Rec".to_string(), fields: f }))
6291 };
6292 let rows: Vec<RuntimeValue> = (0..1000).map(|i| mk(i, i as f64 * 0.5, &format!("t{i}"))).collect();
6293 let eager = ListRepr::from_values(rows);
6294 let list = RuntimeValue::List(Rc::new(RefCell::new(eager.clone())));
6295 let bytes = with_struct_view(true, || {
6296 message_to_wire_with("p", &list, WireCodec::Native, WireIntegrity::Raw).unwrap()
6297 });
6298
6299 let lazy = ListRepr::from_record_list_view(Rc::new(bytes)).expect("wraps as a lazy view");
6300 assert_eq!(lazy.len(), 1000, "len is O(1) from the header — no rows decoded");
6301
6302 assert_eq!(lazy.get_field(0, "id"), Some(RuntimeValue::Int(0)));
6304 assert_eq!(lazy.get_field(999, "id"), Some(RuntimeValue::Int(999)));
6305 assert_eq!(lazy.get_field(500, "x"), Some(RuntimeValue::Float(250.0)));
6306 match lazy.get_field(7, "tag") {
6307 Some(RuntimeValue::Text(s)) => assert_eq!(&*s, "t7"),
6308 o => panic!("expected tag text, got {o:?}"),
6309 }
6310 assert_eq!(lazy.get_field(0, "missing"), None, "missing field is None");
6311
6312 match lazy.get(3) {
6314 Some(RuntimeValue::Struct(s)) => {
6315 assert_eq!(s.type_name, "Rec");
6316 assert_eq!(s.fields.get("id"), Some(&RuntimeValue::Int(3)));
6317 assert_eq!(s.fields.get("x"), Some(&RuntimeValue::Float(1.5)));
6318 }
6319 o => panic!("expected struct row, got {o:?}"),
6320 }
6321
6322 fn struct_eq(a: &RuntimeValue, b: &RuntimeValue) -> bool {
6326 match (a, b) {
6327 (RuntimeValue::Struct(x), RuntimeValue::Struct(y)) => {
6328 x.type_name == y.type_name
6329 && x.fields.len() == y.fields.len()
6330 && x.fields.iter().all(|(k, v)| {
6331 y.fields.get(k).is_some_and(|w| crate::semantics::compare::values_equal(v, w))
6332 })
6333 }
6334 _ => crate::semantics::compare::values_equal(a, b),
6335 }
6336 }
6337 let lazy_vals = lazy.to_values();
6338 let eager_vals = eager.to_values();
6339 assert_eq!(lazy_vals.len(), eager_vals.len());
6340 for (idx, (a, b)) in lazy_vals.iter().zip(&eager_vals).enumerate() {
6341 assert!(struct_eq(a, b), "row {idx} differs:\n lazy={a:?}\n eager={b:?}");
6342 }
6343 }
6344
6345 #[test]
6346 fn message_from_wire_view_is_lazy_for_record_lists_eager_otherwise() {
6347 use crate::interpreter::{ListRepr, StructValue};
6351 let mk = |id: i64| {
6352 let mut f = HashMap::new();
6353 f.insert("id".to_string(), RuntimeValue::Int(id));
6354 RuntimeValue::Struct(Box::new(StructValue { type_name: "R".to_string(), fields: f }))
6355 };
6356 let list = RuntimeValue::List(Rc::new(RefCell::new(ListRepr::from_values((0..100).map(mk).collect()))));
6357 let bytes =
6358 with_struct_view(true, || message_to_wire_with("alice", &list, WireCodec::Native, WireIntegrity::Raw).unwrap());
6359
6360 let (from, val) = message_from_wire_view(&bytes).expect("lazy view decode");
6361 assert_eq!(from, "alice", "sender preserved on the lazy path");
6362 match &val {
6363 RuntimeValue::List(rc) => {
6364 assert!(
6365 matches!(&*rc.borrow(), ListRepr::WireStructs { .. }),
6366 "a record list must be held LAZILY (no rows decoded), got {:?}",
6367 rc.borrow()
6368 );
6369 assert_eq!(rc.borrow().len(), 100, "O(1) len, no decode");
6370 assert_eq!(rc.borrow().get_field(42, "id"), Some(RuntimeValue::Int(42)), "in-place field read");
6371 }
6372 o => panic!("expected a lazy list, got {o:?}"),
6373 }
6374
6375 let sbytes = message_to_wire_with("bob", &RuntimeValue::Int(7), WireCodec::Native, WireIntegrity::Raw).unwrap();
6377 let (sfrom, sval) = message_from_wire_view(&sbytes).expect("scalar decode");
6378 assert_eq!(sfrom, "bob");
6379 assert_eq!(sval, RuntimeValue::Int(7), "non-record shape falls back to full decode");
6380 }
6381
6382 #[test]
6383 fn production_receive_path_defers_then_reads_record_list_lazily() {
6384 use crate::interpreter::{ListRepr, StructValue};
6391 let mk = |id: i64, name: &str| {
6392 let mut f = HashMap::new();
6393 f.insert("id".to_string(), RuntimeValue::Int(id));
6394 f.insert("name".to_string(), RuntimeValue::Text(Rc::new(name.to_string())));
6395 RuntimeValue::Struct(Box::new(StructValue { type_name: "User".to_string(), fields: f }))
6396 };
6397 let rows: Vec<RuntimeValue> = (0..500).map(|i| mk(i, &format!("u{i}"))).collect();
6398 let list = RuntimeValue::List(Rc::new(RefCell::new(ListRepr::from_values(rows))));
6399 let frame =
6400 with_struct_view(true, || message_to_wire_with("alice", &list, WireCodec::Native, WireIntegrity::Raw).unwrap());
6401
6402 assert_eq!(peek_deferrable_sender(&frame).as_deref(), Some("alice"), "record list defers at drain");
6404
6405 let lazy = ListRepr::from_record_list_view(Rc::new(frame.clone())).expect("lazy wrap");
6407 assert!(matches!(lazy, ListRepr::WireStructs { .. }), "Await view holds the list lazily");
6408 assert_eq!(lazy.len(), 500, "O(1) len, nothing decoded");
6409 assert_eq!(lazy.get_field(123, "id"), Some(RuntimeValue::Int(123)), "in-place cell read");
6410
6411 let (efrom, eager_val) = message_from_wire(&frame).expect("eager decode");
6413 assert_eq!(efrom, "alice");
6414 let eager_rows = match &eager_val {
6415 RuntimeValue::List(rc) => rc.borrow().to_values(),
6416 o => panic!("expected list, got {o:?}"),
6417 };
6418 let lazy_rows = lazy.to_values();
6419 assert_eq!(lazy_rows.len(), eager_rows.len());
6420 for (idx, (a, b)) in lazy_rows.iter().zip(&eager_rows).enumerate() {
6421 let eq = match (a, b) {
6422 (RuntimeValue::Struct(x), RuntimeValue::Struct(y)) => {
6423 x.type_name == y.type_name
6424 && x.fields.iter().all(|(k, v)| {
6425 y.fields.get(k).is_some_and(|w| crate::semantics::compare::values_equal(v, w))
6426 })
6427 }
6428 _ => false,
6429 };
6430 assert!(eq, "lazy and eager receive must agree at row {idx}");
6431 }
6432
6433 let sframe = message_to_wire_with("bob", &RuntimeValue::Int(7), WireCodec::Native, WireIntegrity::Raw).unwrap();
6435 assert_eq!(peek_deferrable_sender(&sframe), None, "a scalar is not deferred");
6436 }
6437
6438 #[test]
6439 fn lazy_wirecolumn_reads_received_numeric_columns_zero_copy() {
6440 use crate::interpreter::ListRepr;
6444
6445 let ints: Vec<i64> = (0..2000).collect();
6446 let il = RuntimeValue::List(Rc::new(RefCell::new(ListRepr::Ints(ints.clone()))));
6447 let ibytes =
6448 with_struct_view(true, || message_to_wire_with("alice", &il, WireCodec::Native, WireIntegrity::Raw).unwrap());
6449 assert_eq!(peek_deferrable_sender(&ibytes).as_deref(), Some("alice"), "aligned int column defers");
6450 let lazy = ListRepr::from_received_view(Rc::new(ibytes)).expect("lazy int column");
6451 assert!(matches!(lazy, ListRepr::WireColumn { floats: false, .. }), "held as a lazy int column");
6452 assert_eq!(lazy.len(), 2000, "O(1) len, no decode");
6453 assert_eq!(lazy.get(0), Some(RuntimeValue::Int(0)), "zero-copy element read");
6454 assert_eq!(lazy.get(1999), Some(RuntimeValue::Int(1999)));
6455 assert_eq!(lazy.get(2000), None, "out of range");
6456 let vals = lazy.to_values();
6457 assert_eq!(vals.len(), 2000);
6458 assert_eq!(vals[500], RuntimeValue::Int(500));
6459
6460 let floats: Vec<f64> = (0..1000).map(|i| i as f64 * 0.25).collect();
6461 let fl = RuntimeValue::List(Rc::new(RefCell::new(ListRepr::Floats(floats.clone()))));
6462 let fbytes =
6463 with_struct_view(true, || message_to_wire_with("bob", &fl, WireCodec::Native, WireIntegrity::Raw).unwrap());
6464 assert_eq!(peek_deferrable_sender(&fbytes).as_deref(), Some("bob"), "aligned float column defers");
6465 let lazyf = ListRepr::from_received_view(Rc::new(fbytes)).expect("lazy float column");
6466 assert!(matches!(lazyf, ListRepr::WireColumn { floats: true, .. }), "held as a lazy float column");
6467 assert_eq!(lazyf.len(), 1000);
6468 assert_eq!(lazyf.get(4), Some(RuntimeValue::Float(1.0)), "zero-copy float read (0.25*4)");
6469 assert_eq!(lazyf.to_values()[8], RuntimeValue::Float(2.0));
6470 }
6471
6472 #[test]
6473 fn batch_stream_message_round_trips() {
6474 let values = vec![
6477 RuntimeValue::Int(1),
6478 RuntimeValue::Int(-42),
6479 RuntimeValue::Text(Rc::new("hi".to_string())),
6480 RuntimeValue::Bool(true),
6481 ];
6482 let blob = frame_stream_message("alice", &values).expect("frames a stream");
6483 assert_eq!(peek_stream_sender(&blob).as_deref(), Some("alice"), "sender peekable at drain");
6484
6485 let got = deframe_stream_message(&blob).expect("deframes the stream");
6486 assert_eq!(got.len(), 4);
6487 assert_eq!(got[0], RuntimeValue::Int(1));
6488 assert_eq!(got[1], RuntimeValue::Int(-42));
6489 match &got[2] {
6490 RuntimeValue::Text(t) => assert_eq!(&**t, "hi"),
6491 o => panic!("expected text, got {o:?}"),
6492 }
6493 assert_eq!(got[3], RuntimeValue::Bool(true));
6494
6495 let normal = message_to_wire("p", &RuntimeValue::Int(5)).unwrap();
6497 assert_eq!(peek_stream_sender(&normal), None, "a normal message is not a stream");
6498 assert_eq!(deframe_stream_message(&normal), None);
6499
6500 let empty = frame_stream_message("bob", &[]).unwrap();
6502 assert_eq!(peek_stream_sender(&empty).as_deref(), Some("bob"));
6503 assert_eq!(deframe_stream_message(&empty), Some(vec![]));
6504 }
6505
6506 #[test]
6507 fn build_in_place_edge_cases() {
6508 let empty: Vec<i64> = vec![];
6511 let one: Vec<i64> = vec![42];
6512 let bytes = build_columnar_record(
6513 "",
6514 "E",
6515 &[("z", WireColumn::Ints(&empty)), ("o", WireColumn::Ints(&one))],
6516 );
6517 let view = view_message(&bytes).unwrap();
6518 assert_eq!(view.struct_field("z").unwrap().as_i64_slice().expect("empty is still aligned"), &[] as &[i64]);
6519 assert_eq!(view.struct_field("o").unwrap().as_i64_slice().expect("singleton zero-copy"), &[42]);
6520 assert!(view.struct_field("missing").is_none(), "a missing field is None, not a panic");
6521 }
6522
6523 fn assert_roundtrips(v: &RuntimeValue) -> RtPayload {
6528 let p = materialize(v).expect("materialize");
6529 let back = rebuild(p.clone());
6530 let p2 = materialize(&back).expect("re-materialize");
6531 assert_eq!(p, p2, "marshalling round-trip changed the value");
6532 p
6533 }
6534
6535 fn affine_roundtrip(v: &[i64], s: WireStructure) -> (Vec<u8>, Vec<i64>) {
6538 let value = RuntimeValue::List(Rc::new(RefCell::new(ListRepr::Ints(v.to_vec()))));
6539 let bytes =
6540 with_structure(s, || message_to_wire_with("", &value, WireCodec::Native, WireIntegrity::Raw).unwrap());
6541 let (_, back) = message_from_wire(&bytes).expect("decode");
6542 let got = match back {
6543 RuntimeValue::List(l) => match &*l.borrow() {
6544 ListRepr::Ints(g) => g.clone(),
6545 _ => panic!("expected an Ints list back"),
6546 },
6547 _ => panic!("expected a List back"),
6548 };
6549 (bytes, got)
6550 }
6551
6552 #[test]
6553 fn affine_int_column_elides_to_a_formula_and_round_trips() {
6554 let v: Vec<i64> = (0..1000).collect();
6555 let (bytes, got) = affine_roundtrip(&v, WireStructure::Affine);
6556 assert!(bytes.len() < 40, "a 1000-element affine column should elide to O(1) bytes; got {}", bytes.len());
6558 assert_eq!(got, v, "affine round-trip must be exact");
6559 }
6560
6561 #[test]
6562 fn non_affine_column_is_not_elided_but_still_round_trips() {
6563 let mut v: Vec<i64> = (0..1000).collect();
6564 v[500] = 999_999; let (bytes, got) = affine_roundtrip(&v, WireStructure::Affine);
6566 assert!(bytes.len() > 500, "a non-affine column must fall back to a real encoding; got {}", bytes.len());
6567 assert_eq!(got, v, "fallback round-trip must be exact");
6568 }
6569
6570 #[test]
6571 fn affine_is_bijective_across_i64_overflow() {
6572 let base = i64::MAX - 3;
6574 let stride = 5i64;
6575 let v: Vec<i64> = (0..100).map(|i| base.wrapping_add((i as i64).wrapping_mul(stride))).collect();
6576 let (_, got) = affine_roundtrip(&v, WireStructure::Affine);
6577 assert_eq!(got, v, "wrapping-affine round-trip must be exact");
6578 }
6579
6580 #[test]
6583 fn wire_auto_delta_wins_on_monotone() {
6584 let v: Vec<i64> = (0..200i64).scan(1000i64, |s, i| { *s += 1 + (i % 3); Some(*s) }).collect();
6586 let (auto, got) = affine_roundtrip(&v, WireStructure::Auto);
6587 let (varint, _) = affine_roundtrip(&v, WireStructure::Off);
6588 assert_eq!(got, v, "delta round-trips bit-exact");
6589 assert!(auto.len() < varint.len(), "Auto ({}) must beat varint ({}) on a monotone column", auto.len(), varint.len());
6590 }
6591
6592 #[test]
6593 fn wire_auto_dod_wins_on_timestamps() {
6594 let v: Vec<i64> = (0..300i64).map(|i| 1_700_000_000 + i * 1000 + (i % 5)).collect();
6596 let (auto, got) = affine_roundtrip(&v, WireStructure::Auto);
6597 let (varint, _) = affine_roundtrip(&v, WireStructure::Off);
6598 assert_eq!(got, v, "delta-of-delta round-trips bit-exact");
6599 assert!(auto.len() < varint.len(), "Auto ({}) must beat varint ({}) on timestamps", auto.len(), varint.len());
6600 }
6601
6602 #[test]
6603 fn wire_auto_for_wins_on_clustered() {
6604 let mut rng = SplitMix64 { state: 0x0000_F00D };
6606 let v: Vec<i64> = (0..400).map(|_| 1_000_000 + (rng.next() % 16) as i64).collect();
6607 let (auto, got) = affine_roundtrip(&v, WireStructure::Auto);
6608 let (varint, _) = affine_roundtrip(&v, WireStructure::Off);
6609 assert_eq!(got, v, "frame-of-reference round-trips bit-exact");
6610 assert!(auto.len() < varint.len(), "Auto ({}) must beat varint ({}) on a clustered column", auto.len(), varint.len());
6611 }
6612
6613 #[test]
6614 fn wire_auto_polynomial_ships_the_generator_not_the_data() {
6615 let v: Vec<i64> = (0..10_000i64).map(|i| 3 * i * i - 5 * i + 7).collect();
6619 let (auto, got) = affine_roundtrip(&v, WireStructure::Auto);
6620 assert_eq!(got, v, "the polynomial column reconstructs bit-exact");
6621 let (varint, _) = affine_roundtrip(&v, WireStructure::Off);
6622 eprintln!(
6623 "polynomial generator: {} values → ours {} B vs raw varint {} B ({}× smaller)",
6624 v.len(),
6625 auto.len(),
6626 varint.len(),
6627 varint.len() / auto.len().max(1)
6628 );
6629 assert!(
6630 auto.len() < varint.len() / 100,
6631 "the generator ({} B) must ship ≪ the data ({} B)",
6632 auto.len(),
6633 varint.len()
6634 );
6635 }
6636
6637 #[test]
6638 fn wire_auto_polynomial_handles_cubic_and_negative_and_overflow() {
6639 let cubic: Vec<i64> = (0..500i64).map(|i| 2 * i * i * i - i * i + 11).collect();
6642 let (_, got) = affine_roundtrip(&cubic, WireStructure::Auto);
6643 assert_eq!(got, cubic, "cubic reconstructs bit-exact");
6644
6645 let overflowing: Vec<i64> = vec![i64::MIN, i64::MAX, i64::MIN, i64::MAX];
6646 let (_, got) = affine_roundtrip(&overflowing, WireStructure::Auto);
6647 assert_eq!(got, overflowing, "an overflowing column still round-trips (via the menu)");
6648
6649 let mut rng = SplitMix64 { state: 0xBADC_0FFE };
6650 let noise: Vec<i64> = (0..500).map(|_| rng.next() as i64).collect();
6651 let (_, got) = affine_roundtrip(&noise, WireStructure::Auto);
6652 assert_eq!(got, noise, "random noise round-trips (no false polynomial detection)");
6653 }
6654
6655 #[test]
6656 fn wire_auto_geometric_ships_the_generator_not_the_data() {
6657 let doubling: Vec<i64> = (0..40).map(|i| 3i64 * (1i64 << i)).collect();
6662 let (bytes, got) = affine_roundtrip(&doubling, WireStructure::Auto);
6663 assert_eq!(got, doubling, "a geometric column reconstructs bit-exact");
6664 assert!(
6665 bytes.len() < 20,
6666 "the geometric GENERATOR ships ~3 numbers, not 40 growing values: {} bytes",
6667 bytes.len()
6668 );
6669
6670 let alternating: Vec<i64> = {
6672 let mut c = 1i64;
6673 (0..40)
6674 .map(|_| {
6675 let v = c;
6676 c = c.wrapping_mul(-2);
6677 v
6678 })
6679 .collect()
6680 };
6681 let (bytes, got) = affine_roundtrip(&alternating, WireStructure::Auto);
6682 assert_eq!(got, alternating, "a negative-ratio geometric column reconstructs bit-exact");
6683 assert!(bytes.len() < 20, "negative-ratio geometric also ships the generator: {} bytes", bytes.len());
6684
6685 let wrapping: Vec<i64> = {
6689 let mut c = 1i64;
6690 (0..70)
6691 .map(|_| {
6692 let v = c;
6693 c = c.wrapping_mul(2);
6694 v
6695 })
6696 .collect()
6697 };
6698 let (_, got) = affine_roundtrip(&wrapping, WireStructure::Auto);
6699 assert_eq!(got, wrapping, "an overflowing geometric column still round-trips exactly");
6700
6701 let mut rng = SplitMix64 { state: 0x6E0_47E7 };
6704 let noise: Vec<i64> = (0..500).map(|_| rng.next() as i64).collect();
6705 let (_, got) = affine_roundtrip(&noise, WireStructure::Auto);
6706 assert_eq!(got, noise, "random noise round-trips (no false geometric detection)");
6707
6708 let mut perturbed: Vec<i64> = (0..30).map(|i| 5i64 * (1i64 << i)).collect();
6709 perturbed[17] += 1; let (_, got) = affine_roundtrip(&perturbed, WireStructure::Auto);
6711 assert_eq!(got, perturbed, "a perturbed near-geometric column round-trips (verification rejects it)");
6712
6713 let affine: Vec<i64> = (0..40).map(|i| 7 + 3 * i).collect();
6714 let (_, got) = affine_roundtrip(&affine, WireStructure::Auto);
6715 assert_eq!(got, affine, "an affine column round-trips (geometric does not steal it)");
6716 }
6717
6718 #[test]
6719 fn wire_auto_periodic_ships_the_repeating_block() {
6720 let block = [10i64, 20, 30, 40, 50];
6724 let cyclic: Vec<i64> = (0..500).map(|i| block[i % block.len()]).collect();
6725 let (bytes, got) = affine_roundtrip(&cyclic, WireStructure::Auto);
6726 assert_eq!(got, cyclic, "a periodic column reconstructs bit-exact");
6727 assert!(
6728 bytes.len() < 30,
6729 "the periodic GENERATOR ships ONE period ({} values), not 500: {} bytes",
6730 block.len(),
6731 bytes.len()
6732 );
6733
6734 let block2 = [-7i64, 0, 1000000, -3, 42, 42, -1];
6736 let cyclic2: Vec<i64> = (0..1001).map(|i| block2[i % block2.len()]).collect();
6737 let (bytes, got) = affine_roundtrip(&cyclic2, WireStructure::Auto);
6738 assert_eq!(got, cyclic2, "a mixed-magnitude periodic column reconstructs bit-exact");
6739 assert!(bytes.len() < 40, "still ships ONE period, not 1001 values: {} bytes", bytes.len());
6740
6741 let p5: Vec<i64> = (0..200).map(|i| block[i % 5]).collect();
6744 let (_, got) = affine_roundtrip(&p5, WireStructure::Auto);
6745 assert_eq!(got, p5, "the minimal period round-trips");
6746
6747 let mut rng = SplitMix64 { state: 0x9E15_AB0 };
6750 let noise: Vec<i64> = (0..500).map(|_| rng.next() as i64).collect();
6751 let (_, got) = affine_roundtrip(&noise, WireStructure::Auto);
6752 assert_eq!(got, noise, "random noise round-trips (no false periodic detection)");
6753
6754 let aperiodic: Vec<i64> = (0..50).map(|i| i * i + 1).collect();
6755 let (_, got) = affine_roundtrip(&aperiodic, WireStructure::Auto);
6756 assert_eq!(got, aperiodic, "an aperiodic column round-trips");
6757 }
6758
6759 #[test]
6760 fn wire_float_default_dial_is_pure_memcpy() {
6761 let shapes: Vec<(&str, Vec<f64>)> = vec![
6767 ("constant", vec![3.14159f64; 1000]),
6768 ("affine", (0..1000).map(|i| i as f64).collect()),
6769 ("periodic", (0..1000).map(|i| [1.5f64, -2.25, 3.0, 0.0, 99.99][i % 5]).collect()),
6770 ];
6771 for (name, v) in &shapes {
6772 let val = RuntimeValue::List(Rc::new(RefCell::new(ListRepr::Floats(v.clone()))));
6773 let bytes = message_to_wire_with("", &val, WireCodec::Native, WireIntegrity::Raw).unwrap();
6774 assert!(
6777 bytes.len() >= v.len() * 8,
6778 "[{name}] the Off dial must ship the raw memcpy (≥ {} B), got {} B (detection leaked into the hot path)",
6779 v.len() * 8,
6780 bytes.len()
6781 );
6782 let got = match message_from_wire(&bytes).unwrap().1 {
6783 RuntimeValue::List(l) => match &*l.borrow() {
6784 ListRepr::Floats(g) => g.clone(),
6785 _ => panic!("expected Floats"),
6786 },
6787 _ => panic!("expected List"),
6788 };
6789 assert_eq!(&got, v, "[{name}] memcpy float column round-trips bit-exact");
6790 }
6791 let c = vec![3.14159f64; 1000];
6793 let val = RuntimeValue::List(Rc::new(RefCell::new(ListRepr::Floats(c))));
6794 let small = with_structure(WireStructure::Auto, || {
6795 message_to_wire_with("", &val, WireCodec::Native, WireIntegrity::Raw).unwrap()
6796 });
6797 assert!(small.len() < 30, "Auto still ships the generator (one f64 + count): {} B", small.len());
6798 }
6799
6800 #[test]
6801 fn wire_float_const_and_affine_ship_the_generator() {
6802 fn roundtrip(v: Vec<f64>) -> (Vec<u8>, Vec<f64>) {
6805 let val = RuntimeValue::List(Rc::new(RefCell::new(ListRepr::Floats(v))));
6806 let bytes = with_structure(WireStructure::Auto, || {
6809 message_to_wire_with("", &val, WireCodec::Native, WireIntegrity::Raw).unwrap()
6810 });
6811 let got = match message_from_wire(&bytes).unwrap().1 {
6812 RuntimeValue::List(l) => match &*l.borrow() {
6813 ListRepr::Floats(g) => g.clone(),
6814 _ => panic!("expected Floats"),
6815 },
6816 _ => panic!("expected List"),
6817 };
6818 (bytes, got)
6819 }
6820
6821 let c = vec![3.14159f64; 1000];
6823 let (bytes, got) = roundtrip(c.clone());
6824 assert_eq!(got, c, "constant float column reconstructs");
6825 assert!(bytes.len() < 30, "constant ships one f64 + count, not 8000 B: {} B", bytes.len());
6826
6827 let ints: Vec<f64> = (0..1000).map(|i| i as f64).collect();
6829 let (bytes, got) = roundtrip(ints.clone());
6830 assert_eq!(got, ints, "integer-valued float column reconstructs bit-exact");
6831 assert!(bytes.len() < 40, "affine ships 3 numbers, not 8000 B: {} B", bytes.len());
6832
6833 let half: Vec<f64> = (0..500).map(|i| (i as f64) * 0.5).collect();
6835 let (bytes, got) = roundtrip(half.clone());
6836 assert_eq!(got, half, "power-of-two-stride affine reconstructs bit-exact");
6837 assert!(bytes.len() < 40, "still 3 numbers: {} B", bytes.len());
6838
6839 let mut rng = SplitMix64 { state: 0xF10A7_C0DE };
6842 let noise: Vec<f64> = (0..500).map(|_| (rng.next() % 10_000_000) as f64 / 13.0).collect();
6843 let (_, got) = roundtrip(noise.clone());
6844 assert_eq!(got, noise, "noisy floats round-trip (no false generator detection)");
6845
6846 let mut perturbed: Vec<f64> = (0..50).map(|i| i as f64).collect();
6847 perturbed[37] = 36.9999999;
6848 let (_, got) = roundtrip(perturbed.clone());
6849 assert_eq!(got, perturbed, "a perturbed near-affine column round-trips");
6850 }
6851
6852 #[test]
6853 fn wire_auto_sparse_column_ships_dominant_plus_exceptions() {
6854 let mut v = vec![0i64; 1000];
6858 for k in 0..10 {
6859 v[k * 97] = (k as i64 + 1) * 12345;
6860 }
6861 let (bytes, got) = affine_roundtrip(&v, WireStructure::Auto);
6862 assert_eq!(got, v, "sparse column reconstructs exactly");
6863 assert!(bytes.len() < 80, "sparse ships ~10 exceptions, not 1000 values: {} bytes", bytes.len());
6864
6865 let mut v2 = vec![42i64; 500];
6867 for k in 0..5 {
6868 v2[k * 80 + 3] = -(k as i64 + 1) * 7_000_003;
6869 }
6870 let (bytes, got) = affine_roundtrip(&v2, WireStructure::Auto);
6871 assert_eq!(got, v2, "non-zero-dominant sparse column reconstructs exactly");
6872 assert!(bytes.len() < 80, "still ~5 exceptions: {} bytes", bytes.len());
6873
6874 let mut rng = SplitMix64 { state: 0x5A95E_C0DE };
6877 let noise: Vec<i64> = (0..500).map(|_| rng.next() as i64).collect();
6878 let (_, got) = affine_roundtrip(&noise, WireStructure::Auto);
6879 assert_eq!(got, noise, "random column round-trips (no false sparse detection)");
6880 }
6881
6882 #[test]
6883 fn wire_float_sparse_column_ships_dominant_plus_exceptions() {
6884 fn roundtrip(v: Vec<f64>) -> (Vec<u8>, Vec<f64>) {
6887 let val = RuntimeValue::List(Rc::new(RefCell::new(ListRepr::Floats(v))));
6888 let bytes = with_structure(WireStructure::Auto, || {
6891 message_to_wire_with("", &val, WireCodec::Native, WireIntegrity::Raw).unwrap()
6892 });
6893 let got = match message_from_wire(&bytes).unwrap().1 {
6894 RuntimeValue::List(l) => match &*l.borrow() {
6895 ListRepr::Floats(g) => g.clone(),
6896 _ => panic!("expected Floats"),
6897 },
6898 _ => panic!("expected List"),
6899 };
6900 (bytes, got)
6901 }
6902
6903 let mut v = vec![0.0f64; 1000];
6904 for k in 0..10 {
6905 v[k * 97] = (k as f64 + 1.0) * 1234.5;
6906 }
6907 let (bytes, got) = roundtrip(v.clone());
6908 assert_eq!(got, v, "sparse float column reconstructs exactly");
6909 assert!(bytes.len() < 160, "sparse ships ~10 outliers, not 8000 B: {} B", bytes.len());
6910
6911 let mut v2 = vec![3.5f64; 500];
6913 for k in 0..5 {
6914 v2[k * 80 + 3] = -(k as f64 + 1.0) * 99.0;
6915 }
6916 let (_, got) = roundtrip(v2.clone());
6917 assert_eq!(got, v2, "non-zero-dominant sparse float column reconstructs exactly");
6918
6919 let mut rng = SplitMix64 { state: 0xF10A7_5A95E };
6921 let noise: Vec<f64> = (0..500).map(|_| (rng.next() % 10_000_000) as f64 / 13.0).collect();
6922 let (_, got) = roundtrip(noise.clone());
6923 assert_eq!(got, noise, "random float column round-trips (no false sparse detection)");
6924 }
6925
6926 #[test]
6927 fn wire_float_periodic_and_geometric_ship_the_generator() {
6928 fn roundtrip(v: Vec<f64>) -> (Vec<u8>, Vec<f64>) {
6929 let val = RuntimeValue::List(Rc::new(RefCell::new(ListRepr::Floats(v))));
6930 let bytes = with_structure(WireStructure::Auto, || {
6933 message_to_wire_with("", &val, WireCodec::Native, WireIntegrity::Raw).unwrap()
6934 });
6935 let got = match message_from_wire(&bytes).unwrap().1 {
6936 RuntimeValue::List(l) => match &*l.borrow() {
6937 ListRepr::Floats(g) => g.clone(),
6938 _ => panic!("expected Floats"),
6939 },
6940 _ => panic!("expected List"),
6941 };
6942 (bytes, got)
6943 }
6944
6945 let block = [1.5f64, -2.25, 3.0, 0.0, 99.99];
6947 let cyclic: Vec<f64> = (0..1000).map(|i| block[i % 5]).collect();
6948 let (bytes, got) = roundtrip(cyclic.clone());
6949 assert_eq!(got, cyclic, "periodic float column reconstructs");
6950 assert!(bytes.len() < 80, "ships one 5-float block, not 1000: {} B", bytes.len());
6951
6952 let doubling: Vec<f64> = {
6954 let mut c = 1.0f64;
6955 (0..50).map(|_| { let x = c; c *= 2.0; x }).collect()
6956 };
6957 let (bytes, got) = roundtrip(doubling.clone());
6958 assert_eq!(got, doubling, "doubling float column reconstructs bit-exact");
6959 assert!(bytes.len() < 40, "geometric ships base+ratio+count: {} B", bytes.len());
6960
6961 let halving: Vec<f64> = {
6962 let mut c = 1024.0f64;
6963 (0..40).map(|_| { let x = c; c *= 0.5; x }).collect()
6964 };
6965 let (_, got) = roundtrip(halving.clone());
6966 assert_eq!(got, halving, "halving (exponential decay) reconstructs bit-exact");
6967
6968 let mut rng = SplitMix64 { state: 0xC0FFEE_F10A7 };
6970 let noise: Vec<f64> = (0..500).map(|_| (rng.next() % 9_999_991) as f64 / 7.0 - 1234.5).collect();
6971 let (_, got) = roundtrip(noise.clone());
6972 assert_eq!(got, noise, "random floats round-trip (no false periodic/geometric detection)");
6973 }
6974
6975 #[test]
6976 fn wire_string_template_ships_prefix_suffix_and_affine_index() {
6977 fn roundtrip(strings: &[String]) -> (Vec<u8>, Vec<String>) {
6980 let items: Vec<RuntimeValue> =
6981 strings.iter().map(|s| RuntimeValue::Text(Rc::new(s.clone()))).collect();
6982 let val = RuntimeValue::List(Rc::new(RefCell::new(ListRepr::from_values(items))));
6983 let bytes = with_structure(WireStructure::Auto, || {
6984 message_to_wire_with("", &val, WireCodec::Native, WireIntegrity::Raw).unwrap()
6985 });
6986 let got = match message_from_wire(&bytes).unwrap().1 {
6987 RuntimeValue::List(l) => {
6988 let b = l.borrow();
6989 (0..b.len())
6990 .map(|i| match b.get(i).unwrap() {
6991 RuntimeValue::Text(s) => (*s).clone(),
6992 other => panic!("expected Text, got {other:?}"),
6993 })
6994 .collect()
6995 }
6996 _ => panic!("expected List"),
6997 };
6998 (bytes, got)
6999 }
7000
7001 let urls: Vec<String> = (0..1000).map(|i| format!("https://api.example.com/v1/items/{i}")).collect();
7003 let (bytes, got) = roundtrip(&urls);
7004 assert_eq!(got, urls, "templated URLs reconstruct exactly");
7005 assert!(bytes.len() < 80, "ships prefix + affine index, not 1000 URLs: {} bytes", bytes.len());
7006
7007 let stepped: Vec<String> = (0..500).map(|i| format!("row_{}", i * 2)).collect();
7009 let (_, got) = roundtrip(&stepped);
7010 assert_eq!(got, stepped, "stride-2 templated labels reconstruct exactly");
7011
7012 let files: Vec<String> = (0..300).map(|i| format!("file_{i}.txt")).collect();
7013 let (bytes, got) = roundtrip(&files);
7014 assert_eq!(got, files, "prefix+suffix template reconstructs exactly");
7015 assert!(bytes.len() < 60, "prefix+suffix template stays tiny: {} bytes", bytes.len());
7016
7017 let mut rng = SplitMix64 { state: 0x57117_C0DE };
7020 let scattered: Vec<String> = (0..200).map(|_| format!("k{}", rng.next() % 1_000_000)).collect();
7021 let (_, got) = roundtrip(&scattered);
7022 assert_eq!(got, scattered, "non-affine ids round-trip (no false template)");
7023
7024 let padded: Vec<String> = (0..50).map(|i| format!("id_{i:03}")).collect();
7025 let (_, got) = roundtrip(&padded);
7026 assert_eq!(got, padded, "zero-padded ids round-trip (not templated — exact-decimal guard)");
7027 }
7028
7029 #[test]
7030 fn wire_string_front_coding_crushes_sorted_shared_prefix_columns() {
7031 fn roundtrip(strings: &[String]) -> (Vec<u8>, Vec<String>) {
7035 let items: Vec<RuntimeValue> =
7036 strings.iter().map(|s| RuntimeValue::Text(Rc::new(s.clone()))).collect();
7037 let val = RuntimeValue::List(Rc::new(RefCell::new(ListRepr::from_values(items))));
7038 let bytes = with_structure(WireStructure::Auto, || {
7039 message_to_wire_with("", &val, WireCodec::Native, WireIntegrity::Raw).unwrap()
7040 });
7041 let got = match message_from_wire(&bytes).unwrap().1 {
7042 RuntimeValue::List(l) => {
7043 let b = l.borrow();
7044 (0..b.len())
7045 .map(|i| match b.get(i).unwrap() {
7046 RuntimeValue::Text(s) => (*s).clone(),
7047 other => panic!("expected Text, got {other:?}"),
7048 })
7049 .collect()
7050 }
7051 _ => panic!("expected List"),
7052 };
7053 (bytes, got)
7054 }
7055 let flat_len = |v: &[String]| -> usize { v.iter().map(|s| s.len()).sum() };
7056
7057 let paths: Vec<String> = (0..500).map(|i| format!("/var/log/app/2026/06/service-{i:04}.log")).collect();
7060 let (bytes, got) = roundtrip(&paths);
7061 assert_eq!(got, paths, "front-coded log paths reconstruct exactly");
7062 assert!(
7063 bytes.len() * 3 < flat_len(&paths),
7064 "front-coding crushes the shared path prefix: {} vs flat {}",
7065 bytes.len(),
7066 flat_len(&paths)
7067 );
7068
7069 let mut keys: Vec<String> = Vec::new();
7071 for user in ["alice", "bob", "carol", "dave"] {
7072 for kind in ["profile", "settings", "avatar", "session"] {
7073 keys.push(format!("users/{user}/{kind}/data.json"));
7074 }
7075 }
7076 keys.sort();
7077 let (bytes, got) = roundtrip(&keys);
7078 assert_eq!(got, keys, "front-coded hierarchical keys reconstruct exactly");
7079 assert!(bytes.len() < flat_len(&keys), "front-coding beats flat on hierarchical keys");
7080
7081 let unicode: Vec<String> = (0..100).map(|i| format!("café/naïve/Москва/key-{i:03}")).collect();
7084 let (_, got) = roundtrip(&unicode);
7085 assert_eq!(got, unicode, "front-coding cuts on UTF-8 char boundaries (no corruption)");
7086
7087 let mut rng = SplitMix64 { state: 0xF20D_C0DE };
7090 let scattered: Vec<String> = (0..200)
7091 .map(|_| {
7092 let len = 6 + (rng.next() % 10) as usize;
7093 (0..len).map(|_| (b'a' + (rng.next() % 26) as u8) as char).collect()
7094 })
7095 .collect();
7096 let (_, got) = roundtrip(&scattered);
7097 assert_eq!(got, scattered, "prefix-free random strings round-trip (front-coding not falsely applied)");
7098 }
7099
7100 #[test]
7101 fn wire_bool_generators_ship_constant_alternating_and_run_columns() {
7102 fn roundtrip(v: &[bool]) -> (Vec<u8>, Vec<bool>) {
7106 let val = RuntimeValue::List(Rc::new(RefCell::new(ListRepr::Bools(v.to_vec()))));
7107 let bytes = with_structure(WireStructure::Auto, || {
7108 message_to_wire_with("", &val, WireCodec::Native, WireIntegrity::Raw).unwrap()
7109 });
7110 let got = match message_from_wire(&bytes).unwrap().1 {
7111 RuntimeValue::List(l) => match &*l.borrow() {
7112 ListRepr::Bools(b) => b.clone(),
7113 other => panic!("expected Bools, got {other:?}"),
7114 },
7115 _ => panic!("expected List"),
7116 };
7117 (bytes, got)
7118 }
7119
7120 for constant in [true, false] {
7122 let col = vec![constant; 1000];
7123 let (bytes, got) = roundtrip(&col);
7124 assert_eq!(got, col, "constant bool column reconstructs exactly");
7125 assert!(bytes.len() < 20, "constant={constant} ships a period-1 generator: {} bytes", bytes.len());
7126 }
7127
7128 let alt: Vec<bool> = (0..1000).map(|i| i % 2 == 0).collect();
7130 let (bytes, got) = roundtrip(&alt);
7131 assert_eq!(got, alt, "alternating reconstructs exactly");
7132 assert!(bytes.len() < 20, "alternating ships a period-2 generator: {} bytes", bytes.len());
7133
7134 let weekly: Vec<bool> = (0..700).map(|i| [true, true, true, true, true, false, false][i % 7]).collect();
7135 let (bytes, got) = roundtrip(&weekly);
7136 assert_eq!(got, weekly, "weekly flag reconstructs exactly");
7137 assert!(bytes.len() < 20, "period-7 weekly flag ships as periodic: {} bytes", bytes.len());
7138
7139 let runs: Vec<bool> = (0..1000).map(|i| i >= 500).collect();
7141 let (bytes, got) = roundtrip(&runs);
7142 assert_eq!(got, runs, "two big runs reconstruct exactly");
7143 assert!(bytes.len() < 20, "two big runs ship as RLE: {} bytes", bytes.len());
7144
7145 let mut mostly = vec![true; 1000];
7147 for k in [37, 199, 450, 777, 988] {
7148 mostly[k] = false;
7149 }
7150 let (bytes, got) = roundtrip(&mostly);
7151 assert_eq!(got, mostly, "mostly-true-with-flips reconstructs exactly");
7152 assert!(bytes.len() < 60, "a handful of flips ships as RLE, not 125 packed bytes: {} bytes", bytes.len());
7153
7154 let mut rng = SplitMix64 { state: 0xB001_C0DE_F00D };
7156 let random: Vec<bool> = (0..1000).map(|_| rng.next() & 1 == 0).collect();
7157 let (bytes, got) = roundtrip(&random);
7158 assert_eq!(got, random, "random bools round-trip (no false generator detection)");
7159 assert!(bytes.len() >= 100, "random bools fall back to the bit-pack, not a false generator: {} bytes", bytes.len());
7160
7161 for edge in [vec![], vec![true], vec![false], vec![true, false], vec![false, false, false]] {
7163 let (_, got) = roundtrip(&edge);
7164 assert_eq!(got, edge, "bool edge case {edge:?} round-trips");
7165 }
7166 }
7167
7168 #[test]
7169 fn wire_string_affix_ships_common_prefix_and_suffix_with_arbitrary_middles() {
7170 fn roundtrip(strings: &[String]) -> (Vec<u8>, Vec<String>) {
7174 let items: Vec<RuntimeValue> =
7175 strings.iter().map(|s| RuntimeValue::Text(Rc::new(s.clone()))).collect();
7176 let val = RuntimeValue::List(Rc::new(RefCell::new(ListRepr::from_values(items))));
7177 let bytes = with_structure(WireStructure::Auto, || {
7178 message_to_wire_with("", &val, WireCodec::Native, WireIntegrity::Raw).unwrap()
7179 });
7180 let got = match message_from_wire(&bytes).unwrap().1 {
7181 RuntimeValue::List(l) => {
7182 let b = l.borrow();
7183 (0..b.len())
7184 .map(|i| match b.get(i).unwrap() {
7185 RuntimeValue::Text(s) => (*s).clone(),
7186 other => panic!("expected Text, got {other:?}"),
7187 })
7188 .collect()
7189 }
7190 _ => panic!("expected List"),
7191 };
7192 (bytes, got)
7193 }
7194 let flat_len = |v: &[String]| -> usize { v.iter().map(|s| s.len()).sum() };
7195
7196 let names = ["alice", "bob", "charlie", "dave", "erin", "frank", "grace", "heidi"];
7199 let emails: Vec<String> = (0..400)
7200 .map(|i| format!("{}{}@example.com", names[i % names.len()], i))
7201 .collect();
7202 let (bytes, got) = roundtrip(&emails);
7203 assert_eq!(got, emails, "affixed emails reconstruct exactly");
7204 assert!(
7205 bytes.len() * 2 < flat_len(&emails),
7206 "affix ships the shared @example.com suffix once: {} vs flat {}",
7207 bytes.len(),
7208 flat_len(&emails)
7209 );
7210
7211 let stems = ["app", "db", "auth", "cache", "queue", "web", "cron", "mail"];
7213 let files: Vec<String> = (0..400).map(|i| format!("{}-{}.log", stems[i % stems.len()], i * 7)).collect();
7214 let (bytes, got) = roundtrip(&files);
7215 assert_eq!(got, files, "affixed log files reconstruct exactly");
7216 assert!(bytes.len() < flat_len(&files), "affix beats flat on a shared extension");
7217
7218 let mut rng = SplitMix64 { state: 0xAFF1_C0DE };
7220 let wrapped: Vec<String> = (0..300)
7221 .map(|_| format!("https://cdn.example.com/v2/{}/asset.json", rng.next() % 1_000_000))
7222 .collect();
7223 let (bytes, got) = roundtrip(&wrapped);
7224 assert_eq!(got, wrapped, "prefix+suffix wrapped ids reconstruct exactly");
7225 assert!(bytes.len() * 2 < flat_len(&wrapped), "affix crushes the shared URL wrapper");
7226
7227 let mut rng2 = SplitMix64 { state: 0x0FF1_DEAD };
7230 let scattered: Vec<String> = (0..200)
7231 .map(|_| {
7232 let len = 5 + (rng2.next() % 8) as usize;
7233 (0..len).map(|_| (b'a' + (rng2.next() % 26) as u8) as char).collect()
7234 })
7235 .collect();
7236 let (_, got) = roundtrip(&scattered);
7237 assert_eq!(got, scattered, "affix-free random strings round-trip (no false affix)");
7238 }
7239
7240 #[test]
7241 fn wire_gen_expr_substrate_round_trips_and_evaluates() {
7242 let expr = GenExpr::Select {
7247 op: GenCmp::Eq,
7248 lhs: Box::new(GenExpr::Mod(Box::new(GenExpr::Index), Box::new(GenExpr::Const(2)))),
7249 rhs: Box::new(GenExpr::Const(0)),
7250 then: Box::new(GenExpr::Mul(Box::new(GenExpr::Index), Box::new(GenExpr::Const(10)))),
7251 els: Box::new(GenExpr::Add(
7252 Box::new(GenExpr::Mul(Box::new(GenExpr::Index), Box::new(GenExpr::Const(10)))),
7253 Box::new(GenExpr::Const(5)),
7254 )),
7255 };
7256 let expected: Vec<i64> = (0..256i64).map(|i| if i % 2 == 0 { i * 10 } else { i * 10 + 5 }).collect();
7257 for (i, &e) in expected.iter().enumerate() {
7258 assert_eq!(gen_eval(&expr, i as i64), e, "sandbox eval matches at {i}");
7259 }
7260 let mut sbytes = Vec::new();
7261 serialize_gen(&expr, &mut sbytes);
7262 let mut p = 0;
7263 let mut budget = MAX_GEN_NODES;
7264 assert_eq!(deserialize_gen(&sbytes, &mut p, &mut budget, 0), Some(expr.clone()), "GenExpr round-trips");
7265 assert_eq!(p, sbytes.len(), "the tree is self-delimiting (no trailing bytes)");
7266
7267 let mut bytes = vec![T_GEN];
7268 serialize_gen(&expr, &mut bytes);
7269 write_uvarint(expected.len() as u64, &mut bytes);
7270 let mut p = 0;
7271 match native_decode(&bytes, &mut p).expect("T_GEN decodes") {
7272 RuntimeValue::List(l) => match &*l.borrow() {
7273 ListRepr::Ints(got) => assert_eq!(got, &expected, "T_GEN evaluates to the column"),
7274 _ => panic!("expected Ints"),
7275 },
7276 _ => panic!("expected List"),
7277 }
7278 }
7279
7280 #[test]
7281 fn wire_lower_pure_function_to_genexpr() {
7282 use crate::ast::stmt::{BinaryOpKind, Expr, Literal};
7287 use logicaffeine_base::{Arena, Symbol};
7288 fn num<'a>(a: &'a Arena<Expr<'a>>, v: i64) -> &'a Expr<'a> {
7289 a.alloc(Expr::Literal(Literal::Number(v)))
7290 }
7291 fn bin<'a>(a: &'a Arena<Expr<'a>>, op: BinaryOpKind, l: &'a Expr<'a>, r: &'a Expr<'a>) -> &'a Expr<'a> {
7292 a.alloc(Expr::BinaryOp { op, left: l, right: r })
7293 }
7294 let a: Arena<Expr> = Arena::new();
7295 let i = Symbol::from_index(0);
7296 let idx: &Expr = a.alloc(Expr::Identifier(i));
7297 let body = bin(
7299 &a,
7300 BinaryOpKind::Add,
7301 bin(
7302 &a,
7303 BinaryOpKind::Subtract,
7304 bin(&a, BinaryOpKind::Multiply, bin(&a, BinaryOpKind::Multiply, num(&a, 3), idx), idx),
7305 bin(&a, BinaryOpKind::Multiply, num(&a, 5), idx),
7306 ),
7307 num(&a, 7),
7308 );
7309 let g = lower_expr_to_genexpr(body, i).expect("pure arithmetic lowers");
7310 for x in -50..50i64 {
7311 assert_eq!(gen_eval(&g, x), 3 * x * x - 5 * x + 7, "lowered generator matches f at {x}");
7312 }
7313 let other: &Expr = a.alloc(Expr::Identifier(Symbol::from_index(1)));
7314 assert!(lower_expr_to_genexpr(other, i).is_none(), "unknown variable → not shippable");
7315 let call: &Expr = a.alloc(Expr::Call { function: Symbol::from_index(2), args: vec![] });
7316 assert!(lower_expr_to_genexpr(call, i).is_none(), "a function call → not shippable");
7317 }
7318
7319 #[test]
7320 fn wire_computed_function_ships_callable_and_round_trips() {
7321 use crate::ast::stmt::{BinaryOpKind, Expr, Literal};
7325 use logicaffeine_base::{Arena, Symbol};
7326 let a: Arena<Expr> = Arena::new();
7327 let i = Symbol::from_index(0);
7328 let idx: &Expr = a.alloc(Expr::Identifier(i));
7329 let sq: &Expr = a.alloc(Expr::BinaryOp { op: BinaryOpKind::Multiply, left: idx, right: idx });
7330 let one: &Expr = a.alloc(Expr::Literal(Literal::Number(1)));
7331 let body: &Expr = a.alloc(Expr::BinaryOp { op: BinaryOpKind::Add, left: sq, right: one });
7332 let expr = lower_expr_to_genexpr(body, i).expect("f(i)=i*i+1 lowers");
7333
7334 let f = RuntimeValue::Function(Box::new(ClosureValue {
7335 body_index: usize::MAX,
7336 captured_env: std::collections::HashMap::default(),
7337 param_names: vec![i],
7338 generated: Some(Rc::new(expr.clone())),
7339 }));
7340 let bytes = message_to_wire("p", &f).expect("a generated function is sendable");
7341 match message_from_wire(&bytes).unwrap().1 {
7342 RuntimeValue::Function(c) => {
7343 let g = c.generated.expect("decoded function carries its generator");
7344 assert_eq!(&*g, &expr, "the generator round-trips exactly");
7345 assert_eq!(c.param_names.len(), 1, "arity preserved");
7346 for x in -20..20i64 {
7347 assert_eq!(gen_eval(&g, x), x * x + 1, "the shipped function evaluates f(x) on the receiver");
7348 }
7349 }
7350 _ => panic!("expected a Function back"),
7351 }
7352
7353 let plain = RuntimeValue::Function(Box::new(ClosureValue {
7354 body_index: 0,
7355 captured_env: std::collections::HashMap::default(),
7356 param_names: vec![],
7357 generated: None,
7358 }));
7359 assert!(message_to_wire("p", &plain).is_err(), "an un-lowered closure is still not sendable");
7360 }
7361
7362 #[test]
7363 fn receiver_refuses_a_shipped_computation_when_it_declines_code() {
7364 use crate::ast::stmt::{BinaryOpKind, Expr, Literal};
7370 use logicaffeine_base::{Arena, Symbol};
7371 let a: Arena<Expr> = Arena::new();
7372 let i = Symbol::from_index(0);
7373 let idx: &Expr = a.alloc(Expr::Identifier(i));
7374 let one: &Expr = a.alloc(Expr::Literal(Literal::Number(1)));
7375 let body: &Expr = a.alloc(Expr::BinaryOp { op: BinaryOpKind::Add, left: idx, right: one });
7376 let expr = lower_expr_to_genexpr(body, i).expect("f(i)=i+1 lowers");
7377 let f = RuntimeValue::Function(Box::new(ClosureValue {
7378 body_index: usize::MAX,
7379 captured_env: std::collections::HashMap::default(),
7380 param_names: vec![i],
7381 generated: Some(Rc::new(expr)),
7382 }));
7383 let bytes = message_to_wire("p", &f).expect("a generated function is sendable");
7384 assert!(
7386 message_from_wire(&bytes).is_some(),
7387 "by default a shipped computation decodes (inert data until a contract invokes it)"
7388 );
7389 let no_code = ReceiveLimits { accept_computed: false, ..Default::default() };
7391 assert!(
7392 with_receive_limits(no_code, || message_from_wire(&bytes)).is_none(),
7393 "a receiver with accept_computed=false must REFUSE a shipped computation at decode"
7394 );
7395 }
7396
7397 #[test]
7398 fn wire_auto_modular_affine_ships_a_generator() {
7399 let v: Vec<i64> = (0..5000i64).map(|i| 1000 + 7 * (i % 12)).collect();
7401 let (auto, got) = affine_roundtrip(&v, WireStructure::Auto);
7402 assert_eq!(got, v, "the modular-affine column reconstructs bit-exact");
7403 let (varint, _) = affine_roundtrip(&v, WireStructure::Off);
7404 assert!(
7405 auto.len() < varint.len() / 50,
7406 "the generator ({} B) must ship ≪ the data ({} B)",
7407 auto.len(),
7408 varint.len()
7409 );
7410 }
7411
7412 #[test]
7413 fn wire_auto_byte_column_ships_a_tight_zero_copy_blob() {
7414 let mut rng = SplitMix64 { state: 0x6B70_B10B_CAFE_F00D };
7421 let data: Vec<i64> = (0..1000).map(|_| (rng.next() % 256) as i64).collect();
7422 let v = RuntimeValue::List(Rc::new(RefCell::new(ListRepr::Ints(data.clone()))));
7423 let bytes = with_structure(WireStructure::Auto, || message_to_wire("p", &v).unwrap());
7424
7425 match &message_from_wire(&bytes).unwrap().1 {
7426 RuntimeValue::List(l) => match &*l.borrow() {
7427 ListRepr::Ints(g) => assert_eq!(g, &data, "byte column round-trips bit-exact"),
7428 _ => panic!("expected Ints"),
7429 },
7430 _ => panic!("expected List"),
7431 }
7432 assert!(bytes.len() <= data.len() + 32, "tight blob: {} bytes for {} values", bytes.len(), data.len());
7433
7434 let view = view_message(&bytes).unwrap();
7435 let slice = view.as_byte_slice().expect("a byte column reads zero-copy as &[u8]");
7436 assert_eq!(slice.len(), data.len(), "all bytes present");
7437 for (i, &b) in slice.iter().enumerate() {
7438 assert_eq!(b as i64, data[i], "byte {i} matches");
7439 }
7440 let base = bytes.as_ptr() as usize;
7441 let lo = slice.as_ptr() as usize;
7442 assert!(lo >= base && lo < base + bytes.len(), "the &[u8] borrows the message buffer (zero-copy)");
7443
7444 let varint = with_structure(WireStructure::Off, || message_to_wire("p", &v).unwrap());
7445 assert!(bytes.len() < varint.len(), "byte blob ({}) beats varint ({})", bytes.len(), varint.len());
7446 }
7447
7448 #[test]
7449 fn wire_narrow_byte_column_prefers_for_when_smaller() {
7450 let data: Vec<i64> = (0..1000).map(|i: i64| (i * 7).rem_euclid(16)).collect();
7454 let v = RuntimeValue::List(Rc::new(RefCell::new(ListRepr::Ints(data.clone()))));
7455 let bytes = with_structure(WireStructure::Auto, || message_to_wire("p", &v).unwrap());
7456
7457 match &message_from_wire(&bytes).unwrap().1 {
7458 RuntimeValue::List(l) => match &*l.borrow() {
7459 ListRepr::Ints(g) => assert_eq!(g, &data, "narrow byte column round-trips"),
7460 _ => panic!("expected Ints"),
7461 },
7462 _ => panic!("expected List"),
7463 }
7464 assert!(bytes.len() < data.len(), "narrow bytes pack below 1 byte/element ({} for {})", bytes.len(), data.len());
7465 assert!(
7466 view_message(&bytes).unwrap().as_byte_slice().is_none(),
7467 "the narrow column uses FOR/dict, not a T_BYTES blob"
7468 );
7469 }
7470
7471 #[test]
7472 fn wire_gen_decode_rejects_hostile_trees() {
7473 let mut deep = GenExpr::Index;
7477 for _ in 0..(MAX_GEN_DEPTH + 5) {
7478 deep = GenExpr::Add(Box::new(deep), Box::new(GenExpr::Const(1)));
7479 }
7480 let mut sbytes = Vec::new();
7481 serialize_gen(&deep, &mut sbytes);
7482 let mut p = 0;
7483 let mut budget = MAX_GEN_NODES;
7484 assert!(deserialize_gen(&sbytes, &mut p, &mut budget, 0).is_none(), "over-deep tree rejected");
7485
7486 let mut p = 0;
7487 let mut budget = MAX_GEN_NODES;
7488 assert!(deserialize_gen(&[99u8], &mut p, &mut budget, 0).is_none(), "garbage node tag → None");
7489
7490 let mut p = 0;
7491 let mut budget = MAX_GEN_NODES;
7492 assert!(deserialize_gen(&[2u8], &mut p, &mut budget, 0).is_none(), "truncated binary op → None");
7493
7494 let mut p = 0;
7495 assert!(native_decode(&[T_GEN, 99u8, 5u8], &mut p).is_none(), "garbage T_GEN body → None, no panic");
7496 }
7497
7498 #[test]
7499 fn wire_matrix_blast_every_knob_combo_composes() {
7500 fn li(v: Vec<i64>) -> RuntimeValue {
7508 RuntimeValue::List(Rc::new(RefCell::new(ListRepr::Ints(v))))
7509 }
7510 fn lf(v: Vec<f64>) -> RuntimeValue {
7511 RuntimeValue::List(Rc::new(RefCell::new(ListRepr::Floats(v))))
7512 }
7513 fn rec(id: i64, name: &str, active: bool) -> RuntimeValue {
7514 let mut f = HashMap::new();
7515 f.insert("id".to_string(), RuntimeValue::Int(id));
7516 f.insert("name".to_string(), RuntimeValue::Text(Rc::new(name.to_string())));
7517 f.insert("active".to_string(), RuntimeValue::Bool(active));
7518 RuntimeValue::Struct(Box::new(StructValue { type_name: "Rec".to_string(), fields: f }))
7519 }
7520 let names = ["a", "bb", "ccc", "dddd"];
7521 let payloads: Vec<(&str, RuntimeValue)> = vec![
7522 ("scalar int", RuntimeValue::Int(-123456789)),
7523 ("bigint", RuntimeValue::Int(i64::MIN)),
7524 ("text", RuntimeValue::Text(Rc::new("hello, wire".to_string()))),
7525 ("bool", RuntimeValue::Bool(true)),
7526 ("nothing", RuntimeValue::Nothing),
7527 ("random ints", li((0..64).map(|i: i64| i.wrapping_mul(2_654_435_761)).collect())),
7528 ("monotone ints", li((0..64i64).scan(1000i64, |s, i| { *s += 1 + (i % 3); Some(*s) }).collect())),
7529 ("poly ints", li((0..64).map(|i: i64| 3 * i * i - 5 * i + 7).collect())),
7530 ("sawtooth ints", li((0..64).map(|i: i64| 100 + 5 * (i % 9)).collect())),
7531 ("clustered ints", li((0..64).map(|_| 1_000_000).collect())),
7532 ("wide bytes", li((0..64).map(|i: i64| (i * 37 + 128).rem_euclid(256)).collect())),
7533 ("narrow bytes", li((0..64).map(|i: i64| (i * 7).rem_euclid(16)).collect())),
7534 ("floats", lf((0..64).map(|i| i as f64 * 1.5 - 7.0).collect())),
7535 ("special floats", lf(vec![f64::NAN, f64::INFINITY, f64::NEG_INFINITY, -0.0, f64::MIN_POSITIVE])),
7536 ("bools", RuntimeValue::List(Rc::new(RefCell::new(ListRepr::from_values(
7537 (0..64).map(|i| RuntimeValue::Bool(i % 3 == 0)).collect(),
7538 ))))),
7539 ("strings", RuntimeValue::List(Rc::new(RefCell::new(ListRepr::from_values(
7540 (0..64).map(|i| RuntimeValue::Text(Rc::new(names[i % 4].to_string()))).collect(),
7541 ))))),
7542 ("struct", rec(7, "lone", false)),
7543 ("struct list", RuntimeValue::List(Rc::new(RefCell::new(ListRepr::from_values(
7544 (0..16).map(|i| rec(i, names[i as usize % 4], i % 2 == 0)).collect(),
7545 ))))),
7546 ("empty list", li(vec![])),
7547 ("int→int map", {
7548 let mut m = MapStorage::default();
7549 for k in 0..32i64 { m.insert(RuntimeValue::Int(k), RuntimeValue::Int(k * k)); }
7550 RuntimeValue::Map(Rc::new(RefCell::new(m)))
7551 }),
7552 ("int→string map", {
7553 let mut m = MapStorage::default();
7554 for k in 0..16i64 { m.insert(RuntimeValue::Int(k * 10), RuntimeValue::Text(Rc::new(format!("row_{k}")))); }
7555 RuntimeValue::Map(Rc::new(RefCell::new(m)))
7556 }),
7557 ("int→struct map", {
7558 let mut m = MapStorage::default();
7561 for k in 0..8i64 { m.insert(RuntimeValue::Int(k), rec(k, names[k as usize % 4], k % 2 == 0)); }
7562 RuntimeValue::Map(Rc::new(RefCell::new(m)))
7563 }),
7564 ("text→int map", {
7565 let mut m = MapStorage::default();
7566 for k in 0..8i64 { m.insert(RuntimeValue::Text(Rc::new(format!("k{k}"))), RuntimeValue::Int(k)); }
7567 RuntimeValue::Map(Rc::new(RefCell::new(m)))
7568 }),
7569 ];
7570
7571 let canon = |val: &RuntimeValue| -> Vec<u8> {
7574 with_numerics(WireNumerics::Varint, || {
7575 with_structure(WireStructure::Off, || {
7576 with_floats(WireFloats::Memcpy, || {
7577 message_to_wire_with("c", val, WireCodec::Native, WireIntegrity::Raw).unwrap()
7578 })
7579 })
7580 })
7581 };
7582
7583 let mut combos = 0u64;
7584 for (name, v) in &payloads {
7585 let want = canon(v);
7586 for num in [WireNumerics::Varint, WireNumerics::Fixed, WireNumerics::GroupVarint] {
7587 for st in [WireStructure::Off, WireStructure::Affine, WireStructure::Auto] {
7588 for fl in [WireFloats::Memcpy, WireFloats::XorDelta] {
7589 for comp in
7590 [WireCompression::None, WireCompression::Deflate, WireCompression::Lz4, WireCompression::Zstd]
7591 {
7592 for integ in [WireIntegrity::Raw, WireIntegrity::Checked] {
7593 for sv in [false, true] {
7594 let bytes = with_numerics(num, || {
7595 with_structure(st, || {
7596 with_floats(fl, || {
7597 with_compression_codec(comp, || {
7598 with_struct_view(sv, || {
7599 message_to_wire_with("p", v, WireCodec::Native, integ).unwrap()
7600 })
7601 })
7602 })
7603 })
7604 });
7605 let back = message_from_wire(&bytes).unwrap_or_else(|| {
7606 panic!(
7607 "{name} failed to decode under num={num:?} st={st:?} fl={fl:?} \
7608 comp={comp:?} integ={integ:?} sv={sv}"
7609 )
7610 });
7611 assert_eq!(
7612 canon(&back.1),
7613 want,
7614 "{name} corrupted under num={num:?} st={st:?} fl={fl:?} \
7615 comp={comp:?} integ={integ:?} sv={sv}"
7616 );
7617 combos += 1;
7618 }
7619 }
7620 }
7621 }
7622 }
7623 }
7624 }
7625 assert!(combos >= 4000, "matrix should blast thousands of knob combos, ran {combos}");
7626 }
7627
7628 #[test]
7629 fn wire_shared_type_id_composes_with_every_knob() {
7630 fn rec(id: i64, name: &str, active: bool) -> RuntimeValue {
7636 let mut f = HashMap::new();
7637 f.insert("id".to_string(), RuntimeValue::Int(id));
7638 f.insert("name".to_string(), RuntimeValue::Text(Rc::new(name.to_string())));
7639 f.insert("active".to_string(), RuntimeValue::Bool(active));
7640 RuntimeValue::Struct(Box::new(StructValue { type_name: "Rec".to_string(), fields: f }))
7641 }
7642 let names = ["a", "bb", "ccc"];
7643 let payloads = vec![
7644 rec(7, "lone", false),
7645 RuntimeValue::List(Rc::new(RefCell::new(ListRepr::from_values(
7646 (0..12).map(|i| rec(i, names[i as usize % 3], i % 2 == 0)).collect(),
7647 )))),
7648 ];
7649 let mk_reg = || {
7650 WireTypeRegistry::new(vec![(
7651 "Rec".to_string(),
7652 vec!["active".to_string(), "id".to_string(), "name".to_string()],
7653 )])
7654 };
7655 let canon = |val: &RuntimeValue| -> Vec<u8> {
7656 with_numerics(WireNumerics::Varint, || {
7657 with_structure(WireStructure::Off, || {
7658 message_to_wire_with("c", val, WireCodec::Native, WireIntegrity::Raw).unwrap()
7659 })
7660 })
7661 };
7662 let mut combos = 0u32;
7663 for v in &payloads {
7664 let want = canon(v);
7665 for num in [WireNumerics::Varint, WireNumerics::Fixed, WireNumerics::GroupVarint] {
7666 for st in [WireStructure::Off, WireStructure::Affine, WireStructure::Auto] {
7667 for comp in [WireCompression::None, WireCompression::Zstd] {
7668 for integ in [WireIntegrity::Raw, WireIntegrity::Checked] {
7669 for sv in [false, true] {
7670 let enc = || {
7671 with_numerics(num, || {
7672 with_structure(st, || {
7673 with_compression_codec(comp, || {
7674 with_struct_view(sv, || {
7675 message_to_wire_with("p", v, WireCodec::Native, integ).unwrap()
7676 })
7677 })
7678 })
7679 })
7680 };
7681 let bytes = with_type_registry(mk_reg(), enc);
7683 let back = with_type_registry(mk_reg(), || message_from_wire(&bytes))
7684 .expect("a type-id-elided struct decodes with the registry");
7685 assert_eq!(
7686 canon(&back.1),
7687 want,
7688 "shared struct corrupted under num={num:?} st={st:?} comp={comp:?} integ={integ:?} sv={sv}"
7689 );
7690 combos += 1;
7691 }
7692 }
7693 }
7694 }
7695 }
7696 }
7697 assert!(combos >= 100, "shared-knob matrix ran {combos} combos");
7698 }
7699
7700 #[test]
7701 fn wire_auto_rle_wins_on_runs() {
7702 let mut v = Vec::new();
7704 for k in 0..20i64 {
7705 for _ in 0..30 {
7706 v.push(k);
7707 }
7708 }
7709 let (auto, got) = affine_roundtrip(&v, WireStructure::Auto);
7710 let (varint, _) = affine_roundtrip(&v, WireStructure::Off);
7711 assert_eq!(got, v, "run-length round-trips bit-exact");
7712 assert!(auto.len() < varint.len(), "Auto ({}) must beat varint ({}) on runs", auto.len(), varint.len());
7713 }
7714
7715 #[test]
7716 fn wire_auto_dict_wins_on_low_cardinality() {
7717 let mut rng = SplitMix64 { state: 0x0000_BEEF };
7720 let palette = [7i64, 42, 1000, -5, 999_999];
7721 let v: Vec<i64> = (0..500).map(|_| palette[(rng.next() % 5) as usize]).collect();
7722 let (auto, got) = affine_roundtrip(&v, WireStructure::Auto);
7723 let (varint, _) = affine_roundtrip(&v, WireStructure::Off);
7724 assert_eq!(got, v, "dictionary round-trips bit-exact");
7725 assert!(auto.len() < varint.len(), "Auto ({}) must beat varint ({}) on low cardinality", auto.len(), varint.len());
7726 }
7727
7728 #[test]
7729 fn wire_auto_never_worse_than_varint_on_random() {
7730 let mut rng = SplitMix64 { state: 0x00C0_FFEE };
7733 for _ in 0..50 {
7734 let n = (rng.next() % 200) as usize;
7735 let v: Vec<i64> = (0..n).map(|_| rng.next() as i64).collect();
7736 let (auto, got) = affine_roundtrip(&v, WireStructure::Auto);
7737 let (varint, _) = affine_roundtrip(&v, WireStructure::Off);
7738 assert_eq!(got, v, "Auto round-trips bit-exact on random data");
7739 assert!(auto.len() <= varint.len(), "Auto ({}) must never exceed varint ({})", auto.len(), varint.len());
7740 }
7741 }
7742
7743 #[test]
7744 fn wire_auto_decoder_never_panics_on_mutated_menu_messages() {
7745 let mut rng = SplitMix64 { state: 0x00AB_1234 };
7748 let shapes: Vec<Vec<i64>> = vec![
7749 (0..50i64).collect(),
7750 vec![5i64; 80],
7751 (0..60i64).map(|i| 1_000_000 + (i % 8)).collect(),
7752 (0..70i64).map(|i| 1_700_000_000 + i * 7).collect(),
7753 ];
7754 for shape in &shapes {
7755 let value = RuntimeValue::List(Rc::new(RefCell::new(ListRepr::Ints(shape.clone()))));
7756 let base = with_structure(WireStructure::Auto, || {
7757 message_to_wire_with("", &value, WireCodec::Native, WireIntegrity::Raw).unwrap()
7758 });
7759 for _ in 0..2000 {
7760 let mut m = base.clone();
7761 let i = (rng.next() as usize) % m.len();
7762 m[i] ^= (rng.next() & 0xFF) as u8;
7763 let _ = message_from_wire(&m); }
7765 }
7766 }
7767
7768 #[test]
7769 fn wire_intkey_map_decoder_never_panics_on_mutation() {
7770 let mut rng = SplitMix64 { state: 0x00CD_5678 };
7775 let mk_int = {
7776 let mut m = MapStorage::default();
7777 for k in 0..40i64 {
7778 m.insert(RuntimeValue::Int(k), RuntimeValue::Int(k * 3));
7779 }
7780 RuntimeValue::Map(Rc::new(RefCell::new(m)))
7781 };
7782 let mk_text = {
7783 let mut m = MapStorage::default();
7784 for k in 0..12i64 {
7785 m.insert(RuntimeValue::Int(k * 100), RuntimeValue::Text(Rc::new(format!("v{k}"))));
7786 }
7787 RuntimeValue::Map(Rc::new(RefCell::new(m)))
7788 };
7789 let mk_struct = {
7790 let mut m = MapStorage::default();
7791 for k in 0..10i64 {
7792 let mut f = HashMap::new();
7793 f.insert("id".to_string(), RuntimeValue::Int(k));
7794 f.insert("ok".to_string(), RuntimeValue::Bool(k % 2 == 0));
7795 m.insert(
7796 RuntimeValue::Int(k),
7797 RuntimeValue::Struct(Box::new(StructValue { type_name: "R".to_string(), fields: f })),
7798 );
7799 }
7800 RuntimeValue::Map(Rc::new(RefCell::new(m)))
7801 };
7802 for value in [mk_int, mk_text, mk_struct] {
7803 let base =
7804 message_to_wire_with("", &value, WireCodec::Native, WireIntegrity::Raw).unwrap();
7805 for _ in 0..3000 {
7806 let mut b = base.clone();
7807 let i = (rng.next() as usize) % b.len();
7808 b[i] ^= (rng.next() & 0xFF) as u8;
7809 let _ = message_from_wire(&b); }
7811 }
7812 }
7813
7814 fn varint_roundtrip(v: &[i64]) -> (Vec<u8>, Vec<i64>) {
7818 let value = RuntimeValue::List(Rc::new(RefCell::new(ListRepr::Ints(v.to_vec()))));
7819 let bytes = with_structure(WireStructure::Off, || {
7820 message_to_wire_with("", &value, WireCodec::Native, WireIntegrity::Raw).unwrap()
7821 });
7822 let (_, back) = message_from_wire(&bytes).expect("decode");
7823 let got = match back {
7824 RuntimeValue::List(l) => match &*l.borrow() {
7825 ListRepr::Ints(g) => g.clone(),
7826 _ => panic!("expected an Ints list back"),
7827 },
7828 _ => panic!("expected a List back"),
7829 };
7830 (bytes, got)
7831 }
7832
7833 #[test]
7834 fn a_non_negative_int_column_skips_zigzag_for_half_the_size() {
7835 let v = vec![64i64; 100];
7839 let (bytes, got) = varint_roundtrip(&v);
7840 assert_eq!(got, v, "non-negative round-trip must be exact");
7841 assert!(
7842 bytes.len() < 150,
7843 "a non-negative column must use plain LEB128 (≈100B), not zigzag (≈200B); got {} bytes",
7844 bytes.len()
7845 );
7846 }
7847
7848 #[test]
7849 fn a_column_with_any_negative_uses_zigzag_and_round_trips() {
7850 let v = vec![-1i64, -64, 5, -100, 0, 127];
7851 let (_, got) = varint_roundtrip(&v);
7852 assert_eq!(got, v, "mixed-sign round-trip must be exact");
7853 }
7854
7855 #[test]
7856 fn adaptive_sign_mode_round_trips_random_columns() {
7857 let mut rng = 0x1234_5678_9ABC_DEF0u64;
7862 let mut next = || {
7863 rng ^= rng << 13;
7864 rng ^= rng >> 7;
7865 rng ^= rng << 17;
7866 rng
7867 };
7868 for _ in 0..3000 {
7869 let n = (next() % 80) as usize;
7870 let force_nonneg = next() & 1 == 0;
7871 let v: Vec<i64> = (0..n)
7872 .map(|_| {
7873 let r = next() as i64;
7874 if force_nonneg {
7875 r & i64::MAX } else {
7877 r
7878 }
7879 })
7880 .collect();
7881 let (_, got) = varint_roundtrip(&v);
7882 assert_eq!(got, v, "random adaptive sign-mode round-trip failed for {v:?}");
7883 }
7884 }
7885
7886 #[test]
7887 fn adaptive_sign_mode_round_trips_every_boundary() {
7888 let cases: Vec<Vec<i64>> = vec![
7889 vec![],
7890 vec![0i64; 10],
7891 vec![1, 2, 3, 63, 64, 65, 127, 128, 255, 256],
7892 vec![-1, -2, -63, -64, -128, -129],
7893 vec![i64::MIN, i64::MAX, 0, -1, 1],
7894 vec![i64::MAX, i64::MAX - 1], ];
7896 for v in cases {
7897 let (_, got) = varint_roundtrip(&v);
7898 assert_eq!(got, v, "adaptive sign-mode round-trip failed for {v:?}");
7899 }
7900 }
7901
7902 #[test]
7903 fn wireview_reads_any_element_in_place_without_decoding() {
7904 let v: Vec<i64> = (0..1_000_000).map(|i| i as i64 * 3 - 7).collect();
7907 let value = RuntimeValue::List(Rc::new(RefCell::new(ListRepr::Ints(v.clone()))));
7908 let bytes = with_numerics(WireNumerics::Fixed, || {
7909 message_to_wire_with("", &value, WireCodec::Native, WireIntegrity::Raw).unwrap()
7910 });
7911 let view = view_message(&bytes).expect("view opens over the fixed-layout message");
7912 assert_eq!(view.int_list_len(), Some(1_000_000));
7913 for &i in &[0usize, 1, 12_345, 678_901, 999_999] {
7914 assert_eq!(view.int_list_get(i), Some(v[i]), "random-access element {i}");
7915 }
7916 assert_eq!(view.int_list_get(1_000_000), None, "out-of-bounds is None, not a panic");
7917 }
7918
7919 #[test]
7920 fn wireview_varint_and_float_and_scalar_views_agree_with_decode() {
7921 let ints: Vec<i64> = vec![-5, 0, 7, 200, -3000, i64::MAX, i64::MIN];
7924 let iv = RuntimeValue::List(Rc::new(RefCell::new(ListRepr::Ints(ints.clone()))));
7925 let ib = with_numerics(WireNumerics::Varint, || {
7926 message_to_wire_with("", &iv, WireCodec::Native, WireIntegrity::Raw).unwrap()
7927 });
7928 let view = view_message(&ib).unwrap();
7929 assert_eq!(view.int_list_len(), Some(ints.len()));
7930 for (i, &x) in ints.iter().enumerate() {
7931 assert_eq!(view.int_list_get(i), Some(x), "varint element {i}");
7932 }
7933 let flts = vec![1.5f64, -2.25, 3.0e10, f64::MIN, f64::MAX];
7934 let fv = RuntimeValue::List(Rc::new(RefCell::new(ListRepr::Floats(flts.clone()))));
7935 let fb = message_to_wire_with("", &fv, WireCodec::Native, WireIntegrity::Raw).unwrap();
7936 let fview = view_message(&fb).unwrap();
7937 assert_eq!(fview.float_list_len(), Some(flts.len()));
7938 for (i, &x) in flts.iter().enumerate() {
7939 assert_eq!(fview.float_list_get(i), Some(x), "float element {i}");
7940 }
7941 let sb = message_to_wire_with("", &RuntimeValue::Int(-42), WireCodec::Native, WireIntegrity::Raw).unwrap();
7942 assert_eq!(view_message(&sb).unwrap().as_int(), Some(-42));
7943 }
7944
7945 #[test]
7946 fn wireview_single_field_read_is_far_cheaper_than_full_decode() {
7947 let v: Vec<i64> = (0..1_000_000).map(|i| i as i64).collect();
7951 let value = RuntimeValue::List(Rc::new(RefCell::new(ListRepr::Ints(v))));
7952 let bytes = with_numerics(WireNumerics::Fixed, || {
7953 message_to_wire_with("", &value, WireCodec::Native, WireIntegrity::Raw).unwrap()
7954 });
7955 let reads = {
7956 let t = std::time::Instant::now();
7957 for _ in 0..1000 {
7958 let view = view_message(&bytes).unwrap();
7959 std::hint::black_box(view.int_list_get(999_999));
7960 }
7961 t.elapsed().as_nanos()
7962 };
7963 let full = {
7964 let t = std::time::Instant::now();
7965 std::hint::black_box(message_from_wire(&bytes).unwrap());
7966 t.elapsed().as_nanos()
7967 };
7968 assert!(
7969 reads < full,
7970 "1000 zero-copy field reads ({reads}ns) must be cheaper than ONE full decode ({full}ns)"
7971 );
7972 }
7973
7974 #[test]
7975 fn wireview_open_is_o1_even_with_a_checksum() {
7976 let v: Vec<i64> = (0..1_000_000).map(|i| i as i64).collect();
7982 let value = RuntimeValue::List(Rc::new(RefCell::new(ListRepr::Ints(v))));
7983 let bytes = with_numerics(WireNumerics::Fixed, || message_to_wire("", &value).unwrap());
7984 assert!(bytes[0] & H_CHECKED != 0, "the default message carries a checksum");
7985 let reads = {
7986 let t = std::time::Instant::now();
7987 for _ in 0..1000 {
7988 let view = view_message(&bytes).unwrap();
7989 std::hint::black_box(view.int_list_get(999_999));
7990 }
7991 t.elapsed().as_nanos()
7992 };
7993 let full = {
7994 let t = std::time::Instant::now();
7995 std::hint::black_box(message_from_wire(&bytes).unwrap());
7996 t.elapsed().as_nanos()
7997 };
7998 assert!(
7999 reads < full,
8000 "1000 view reads of a checksummed message ({reads}ns) must beat one full decode ({full}ns)"
8001 );
8002 }
8003
8004 #[test]
8005 fn wireview_rejects_compressed_and_malformed() {
8006 let v = RuntimeValue::List(Rc::new(RefCell::new(ListRepr::Ints(
8010 (0..4000).map(|i| (i % 4) as i64 * 1000).collect(),
8011 ))));
8012 let compressed = with_compression_codec(WireCompression::Zstd, || {
8013 message_to_wire_with("", &v, WireCodec::Native, WireIntegrity::Raw).unwrap()
8014 });
8015 assert!(compressed[0] & 0x02 != 0, "the test payload must actually be compressed");
8016 assert!(view_message(&compressed).is_none(), "a compressed message has no in-place view");
8017 assert!(view_message(&[]).is_none(), "empty");
8018 assert!(view_message(&[0xFF, 0x00, 0x01]).is_none(), "garbage header");
8019 }
8020
8021 #[test]
8022 fn structure_off_is_the_default_and_leaves_bytes_unchanged() {
8023 let v: Vec<i64> = (0..50).collect();
8024 let value = RuntimeValue::List(Rc::new(RefCell::new(ListRepr::Ints(v))));
8025 let default = message_to_wire_with("", &value, WireCodec::Native, WireIntegrity::Raw).unwrap();
8026 let (off, _) = {
8027 let b = with_structure(WireStructure::Off, || {
8028 message_to_wire_with("", &value, WireCodec::Native, WireIntegrity::Raw).unwrap()
8029 });
8030 (b, ())
8031 };
8032 assert_eq!(default, off, "Off must equal the default path byte-for-byte (no regression)");
8033 }
8034
8035 fn big(decimal: &str) -> RuntimeValue {
8038 RuntimeValue::from_bigint(logicaffeine_base::BigInt::parse_decimal(decimal).unwrap())
8039 }
8040
8041 #[test]
8042 fn bigint_round_trips_through_the_binary_wire_exactly() {
8043 let v = big("123456789012345678901234567890");
8044 let bytes = message_to_wire("", &v).unwrap();
8045 let (_, back) = message_from_wire(&bytes).unwrap();
8046 assert_eq!(back.to_display_string(), "123456789012345678901234567890");
8047 assert!(matches!(back, RuntimeValue::BigInt(_)), "stays a BigInt across the wire");
8048 }
8049
8050 #[test]
8051 fn negative_bigint_round_trips_through_the_wire() {
8052 let v = big("-99999999999999999999999999999");
8053 let bytes = message_to_wire("", &v).unwrap();
8054 let (_, back) = message_from_wire(&bytes).unwrap();
8055 assert_eq!(back.to_display_string(), "-99999999999999999999999999999");
8056 }
8057
8058 #[test]
8059 fn bigint_round_trips_through_cross_task_materialize_rebuild() {
8060 let v = big("340282366920938463463374607431768211456"); let back = rebuild(materialize(&v).unwrap());
8062 assert_eq!(back.to_display_string(), "340282366920938463463374607431768211456");
8063 }
8064
8065 fn dec_lit(s: &str) -> RuntimeValue {
8068 RuntimeValue::Decimal(Rc::new(logicaffeine_base::Decimal::parse(s).unwrap()))
8069 }
8070
8071 #[test]
8072 fn decimal_round_trips_through_the_binary_wire_preserving_scale() {
8073 for s in ["19.99", "-0.005", "100.00", "0", "0.10", "123456789.000001"] {
8076 let bytes = message_to_wire("", &dec_lit(s)).unwrap();
8077 let (_, back) = message_from_wire(&bytes).unwrap();
8078 assert!(matches!(back, RuntimeValue::Decimal(_)), "stays a Decimal across the wire: {s}");
8079 assert_eq!(back.to_display_string(), s, "scale + value preserved exactly: {s}");
8080 }
8081 }
8082
8083 #[test]
8084 fn decimal_round_trips_through_cross_task_materialize_rebuild() {
8085 let v = dec_lit("19.99");
8086 let back = rebuild(materialize(&v).unwrap());
8087 assert!(matches!(back, RuntimeValue::Decimal(_)));
8088 assert_eq!(back.to_display_string(), "19.99");
8089 }
8090
8091 #[test]
8092 fn decimal_money_survives_wire_where_a_json_float_would_drift() {
8093 let bytes = message_to_wire("", &dec_lit("0.30")).unwrap();
8096 let (_, back) = message_from_wire(&bytes).unwrap();
8097 assert_eq!(back.to_display_string(), "0.30");
8098 assert_ne!(0.1_f64 + 0.2, 0.3);
8099 }
8100
8101 fn cplx(re: (i64, i64), im: (i64, i64)) -> RuntimeValue {
8103 RuntimeValue::Complex(Rc::new(logicaffeine_base::Complex::new(
8104 logicaffeine_base::Rational::from_ratio_i64(re.0, re.1).unwrap(),
8105 logicaffeine_base::Rational::from_ratio_i64(im.0, im.1).unwrap(),
8106 )))
8107 }
8108
8109 #[test]
8110 fn complex_round_trips_through_the_binary_wire_exactly() {
8111 for z in [
8113 cplx((3, 1), (4, 1)), cplx((0, 1), (1, 1)), cplx((0, 1), (-1, 1)), cplx((-1, 2), (3, 4)), cplx((7, 1), (0, 1)), ] {
8119 let bytes = message_to_wire("", &z).unwrap();
8120 let (_, back) = message_from_wire(&bytes).unwrap();
8121 assert!(matches!(back, RuntimeValue::Complex(_)), "stays Complex on the wire");
8122 assert_eq!(back, z, "exact complex survives the wire");
8123 }
8124 }
8125
8126 #[test]
8127 fn complex_round_trips_through_cross_task_materialize_rebuild() {
8128 let z = cplx((3, 1), (-4, 1));
8129 let back = rebuild(materialize(&z).unwrap());
8130 assert!(matches!(back, RuntimeValue::Complex(_)));
8131 assert_eq!(back, z);
8132 }
8133
8134 fn modu(v: i64, n: i64) -> RuntimeValue {
8135 RuntimeValue::Modular(Rc::new(logicaffeine_base::Modular::from_i64(v, n).unwrap()))
8136 }
8137
8138 #[test]
8139 fn modular_round_trips_through_the_binary_wire_preserving_the_ring() {
8140 for z in [modu(3, 7), modu(0, 13), modu(10, 7), modu(123456, 1_000_003)] {
8142 let bytes = message_to_wire("", &z).unwrap();
8143 let (_, back) = message_from_wire(&bytes).unwrap();
8144 assert!(matches!(back, RuntimeValue::Modular(_)), "stays Modular on the wire");
8145 assert_eq!(back, z, "exact residue + modulus survive the wire");
8146 }
8147 }
8148
8149 #[test]
8150 fn modular_round_trips_through_cross_task_materialize_rebuild() {
8151 let z = modu(42, 97);
8152 let back = rebuild(materialize(&z).unwrap());
8153 assert!(matches!(back, RuntimeValue::Modular(_)));
8154 assert_eq!(back, z);
8155 }
8156
8157 fn qty(num: i64, den: i64, unit: &str) -> RuntimeValue {
8159 let unit = logicaffeine_base::quantity::units::by_name(unit).unwrap();
8160 let mag = logicaffeine_base::Rational::new(
8161 logicaffeine_base::BigInt::from_i64(num),
8162 logicaffeine_base::BigInt::from_i64(den),
8163 )
8164 .unwrap();
8165 RuntimeValue::Quantity(Rc::new(crate::interpreter::QuantityValue {
8166 q: logicaffeine_base::Quantity::of(mag, &unit),
8167 unit,
8168 }))
8169 }
8170
8171 #[test]
8172 fn quantity_round_trips_through_the_binary_wire_exactly() {
8173 for (q, shown) in [
8176 (qty(2, 1, "inch"), "2 in"),
8177 (qty(20, 1, "celsius"), "20 °C"),
8178 (qty(5, 1, "kilogram"), "5 kg"),
8179 (qty(42, 127, "foot"), "42/127 ft"),
8180 ] {
8181 let bytes = message_to_wire("", &q).unwrap();
8182 let (_, back) = message_from_wire(&bytes).unwrap();
8183 assert!(matches!(back, RuntimeValue::Quantity(_)), "stays a Quantity on the wire: {shown}");
8184 assert_eq!(back.to_display_string(), shown, "value + unit preserved exactly: {shown}");
8185 assert_eq!(back, q, "physical equality preserved: {shown}");
8186 }
8187 }
8188
8189 #[test]
8190 fn quantity_round_trips_through_cross_task_materialize_rebuild() {
8191 let q = qty(42, 127, "foot");
8192 let back = rebuild(materialize(&q).unwrap());
8193 assert!(matches!(back, RuntimeValue::Quantity(_)));
8194 assert_eq!(back.to_display_string(), "42/127 ft");
8195 assert_eq!(back, q);
8196 }
8197
8198 #[derive(PartialEq, Eq, Debug)]
8207 enum ConfClass {
8208 Value,
8211 Container,
8214 Opaque,
8216 }
8217
8218 fn conformance_class(v: &RuntimeValue) -> ConfClass {
8222 match v {
8223 RuntimeValue::Int(_)
8224 | RuntimeValue::BigInt(_)
8225 | RuntimeValue::Rational(_)
8226 | RuntimeValue::Decimal(_)
8227 | RuntimeValue::Complex(_)
8228 | RuntimeValue::Modular(_)
8229 | RuntimeValue::Float(_)
8230 | RuntimeValue::Bool(_)
8231 | RuntimeValue::Text(_)
8232 | RuntimeValue::Char(_)
8233 | RuntimeValue::Nothing
8234 | RuntimeValue::Duration(_)
8235 | RuntimeValue::Date(_)
8236 | RuntimeValue::Moment(_)
8237 | RuntimeValue::Span { .. }
8238 | RuntimeValue::Time(_)
8239 | RuntimeValue::Word(_)
8240 | RuntimeValue::Quantity(_)
8241 | RuntimeValue::Money(_)
8242 | RuntimeValue::Uuid(_)
8243 | RuntimeValue::Peer(_) => ConfClass::Value,
8244 RuntimeValue::List(_)
8245 | RuntimeValue::Tuple(_)
8246 | RuntimeValue::Set(_)
8247 | RuntimeValue::Map(_)
8248 | RuntimeValue::Struct(_)
8249 | RuntimeValue::Inductive(_) => ConfClass::Container,
8250 RuntimeValue::Function(_)
8251 | RuntimeValue::Chan(_)
8252 | RuntimeValue::TaskHandle(_)
8253 | RuntimeValue::Crdt(_)
8254 | RuntimeValue::Lanes(_) => ConfClass::Opaque,
8259 }
8260 }
8261
8262 fn value_representatives() -> Vec<RuntimeValue> {
8265 vec![
8266 RuntimeValue::Int(7),
8267 RuntimeValue::BigInt(Rc::new(logicaffeine_base::BigInt::from_le_bytes(
8269 false,
8270 &[0, 0, 0, 0, 0, 0, 0, 0, 1],
8271 ))),
8272 RuntimeValue::Rational(Rc::new(
8274 logicaffeine_base::Rational::from_ratio_i64(1, 2).unwrap(),
8275 )),
8276 dec_lit("19.99"),
8277 cplx((3, 1), (4, 1)),
8278 modu(3, 7),
8279 RuntimeValue::Float(2.5),
8280 RuntimeValue::Bool(true),
8281 RuntimeValue::Text(Rc::new("hi".to_string())),
8282 RuntimeValue::Char('x'),
8283 RuntimeValue::Nothing,
8284 RuntimeValue::Duration(10),
8285 RuntimeValue::Date(19_000),
8286 RuntimeValue::Moment(123),
8287 RuntimeValue::Span { months: 3, days: 14 },
8288 RuntimeValue::Time(99),
8289 RuntimeValue::Word(logicaffeine_base::WordVal::from_u64(32, 42).unwrap()),
8290 qty(42, 127, "foot"),
8291 RuntimeValue::Money(Rc::new(logicaffeine_base::Money::of(
8292 logicaffeine_base::Decimal::parse("19.99").unwrap(),
8293 logicaffeine_base::money::currency::by_code("USD").unwrap(),
8294 ))),
8295 RuntimeValue::Uuid(Rc::new(
8296 logicaffeine_base::Uuid::parse("550e8400-e29b-41d4-a716-446655440000").unwrap(),
8297 )),
8298 RuntimeValue::Peer(Rc::new("ws://host:9944".to_string())),
8299 ]
8300 }
8301
8302 #[derive(Debug)]
8304 enum AotWiring {
8305 Rust(&'static str),
8308 RuntimeOnly,
8311 }
8312
8313 fn aot_wiring(v: &RuntimeValue) -> AotWiring {
8319 use AotWiring::{Rust, RuntimeOnly};
8320 match v {
8321 RuntimeValue::Int(_) | RuntimeValue::BigInt(_) => Rust("i64"),
8323 RuntimeValue::Rational(_) => Rust("LogosRational"),
8324 RuntimeValue::Decimal(_) => Rust("LogosDecimal"),
8325 RuntimeValue::Complex(_) => Rust("LogosComplex"),
8326 RuntimeValue::Modular(_) => Rust("LogosModular"),
8327 RuntimeValue::Float(_) => Rust("f64"),
8328 RuntimeValue::Bool(_) => Rust("bool"),
8329 RuntimeValue::Text(_) => Rust("String"),
8330 RuntimeValue::Char(_) => Rust("char"),
8331 RuntimeValue::Nothing => Rust("()"),
8332 RuntimeValue::Duration(_) => Rust("std::time::Duration"),
8333 RuntimeValue::Date(_) => Rust("LogosDate"),
8334 RuntimeValue::Moment(_) => Rust("LogosMoment"),
8335 RuntimeValue::Span { .. } => Rust("LogosSpan"),
8336 RuntimeValue::Time(_) => Rust("LogosTime"),
8337 RuntimeValue::Word(_) => Rust("Word32"),
8339 RuntimeValue::Lanes(_) => Rust("Lanes8Word32"),
8342 RuntimeValue::Quantity(_) => Rust("LogosQuantity"),
8343 RuntimeValue::Money(_) => Rust("LogosMoney"),
8344 RuntimeValue::Uuid(_) => Rust("LogosUuid"),
8345 RuntimeValue::Peer(_) => RuntimeOnly,
8348 RuntimeValue::List(_)
8351 | RuntimeValue::Tuple(_)
8352 | RuntimeValue::Set(_)
8353 | RuntimeValue::Map(_)
8354 | RuntimeValue::Struct(_)
8355 | RuntimeValue::Inductive(_) => RuntimeOnly,
8356 RuntimeValue::Function(_)
8358 | RuntimeValue::Chan(_)
8359 | RuntimeValue::TaskHandle(_)
8360 | RuntimeValue::Crdt(_) => RuntimeOnly,
8361 }
8362 }
8363
8364 fn assert_value_conformance(v: &RuntimeValue) {
8366 let name = v.type_name();
8367 assert!(!name.is_empty(), "type_name must be non-empty");
8368 let _ = v.to_display_string();
8370 assert!(v == v, "{name} value is not equal to itself");
8372 let back = rebuild(materialize(v).unwrap_or_else(|_| panic!("{name} did not materialize")));
8374 assert_eq!(&back, v, "{name} changed across cross-task marshalling");
8375 assert_eq!(
8376 conformance_class(&back),
8377 ConfClass::Value,
8378 "{name} changed variant across marshalling"
8379 );
8380 let bytes = message_to_wire("", v).unwrap_or_else(|_| panic!("{name} did not encode to wire"));
8382 let (_, back2) = message_from_wire(&bytes).unwrap_or_else(|| panic!("{name} did not decode"));
8383 assert_eq!(&back2, v, "{name} changed across the binary wire");
8384 }
8385
8386 #[test]
8387 fn every_value_type_conforms_name_display_eq_and_both_wire_round_trips() {
8388 let reps = value_representatives();
8389 for v in &reps {
8390 assert_eq!(
8391 conformance_class(v),
8392 ConfClass::Value,
8393 "representative for {} must be a Value",
8394 v.type_name()
8395 );
8396 assert_value_conformance(v);
8397 }
8398 assert!(reps.len() >= 20, "expected a representative for every value type");
8400 }
8401
8402 #[test]
8403 fn every_value_type_is_wired_into_the_aot_codegen_tier() {
8404 let mut checked = 0usize;
8413 for v in &value_representatives() {
8414 let name = v.type_name();
8415 if let AotWiring::Rust(expected) = aot_wiring(v) {
8416 let mapped = crate::codegen::types::map_type_to_rust(name);
8417 assert_eq!(
8418 mapped, expected,
8419 "{name}: AOT codegen lowers it to `{mapped}`, but the wiring lock expects `{expected}` \
8420 — wire the type into codegen/types.rs::map_type_to_rust"
8421 );
8422 let lt = crate::analysis::types::LogosType::from_type_name(name);
8427 if lt != crate::analysis::types::LogosType::Unknown {
8428 assert_eq!(
8429 lt.to_rust_type(), expected,
8430 "{name}: analysis LogosType lowers to `{}`, codegen to `{expected}` — the type checker \
8431 and codegen disagree; wire them consistently",
8432 lt.to_rust_type()
8433 );
8434 }
8435 checked += 1;
8436 }
8437 }
8438 assert!(checked >= 18, "AOT wiring lock checked only {checked} value types");
8440 }
8441
8442 #[test]
8443 fn compound_dimension_quantity_survives_the_wire_as_its_signature() {
8444 let m = logicaffeine_base::quantity::units::by_name("meter").unwrap();
8447 let area = logicaffeine_base::Quantity::of(logicaffeine_base::Rational::from_i64(3), &m)
8448 .mul(&logicaffeine_base::Quantity::of(logicaffeine_base::Rational::from_i64(4), &m));
8449 let area_unit =
8450 logicaffeine_base::Unit::linear("", area.dimension(), logicaffeine_base::Rational::one());
8451 let v = RuntimeValue::Quantity(Rc::new(crate::interpreter::QuantityValue { q: area, unit: area_unit }));
8452 let (_, back) = message_from_wire(&message_to_wire("", &v).unwrap()).unwrap();
8453 assert_eq!(back.to_display_string(), "12 L^2");
8454 assert_eq!(back, v);
8455 }
8456
8457 #[test]
8458 fn our_wire_preserves_an_integer_that_json_would_corrupt() {
8459 let n = 9_007_199_254_740_993i64;
8463 let bytes = message_to_wire("", &RuntimeValue::Int(n)).unwrap();
8464 let (_, back) = message_from_wire(&bytes).unwrap();
8465 assert_eq!(back, RuntimeValue::Int(n), "our wire keeps it exact");
8466 assert_ne!(n as f64 as i64, n, "f64 round-trip corrupts 2^53+1 — the JSON footgun");
8468 }
8469
8470 fn rat(n: i64, d: i64) -> RuntimeValue {
8471 RuntimeValue::from_rational(logicaffeine_base::Rational::from_ratio_i64(n, d).unwrap())
8472 }
8473
8474 #[test]
8475 fn our_wire_preserves_a_fraction_that_json_would_round() {
8476 let bytes = message_to_wire("", &rat(1, 3)).unwrap();
8480 let (_, back) = message_from_wire(&bytes).unwrap();
8481 assert_eq!(back.to_display_string(), "1/3", "the fraction survives the wire exactly");
8482 assert!(matches!(back, RuntimeValue::Rational(_)), "stays a Rational across the wire");
8483 assert_ne!(0.1_f64 + 0.2, 0.3);
8485 }
8486
8487 #[test]
8488 fn rational_round_trips_through_the_wire_and_cross_task() {
8489 for (n, d, shown) in [(7i64, 2i64, "7/2"), (-3, 4, "-3/4"), (6, 2, "3"), (22, 7, "22/7")] {
8492 let v = rat(n, d);
8493 let bytes = message_to_wire("", &v).unwrap();
8494 let (_, back) = message_from_wire(&bytes).unwrap();
8495 assert_eq!(back.to_display_string(), shown, "{n}/{d} via the binary wire");
8496 let back2 = rebuild(materialize(&v).unwrap());
8497 assert_eq!(back2.to_display_string(), shown, "{n}/{d} via materialize/rebuild");
8498 }
8499 }
8500
8501 #[test]
8502 fn scalars_and_temporals_roundtrip() {
8503 for v in [
8504 RuntimeValue::Int(5),
8505 RuntimeValue::Float(2.5),
8506 RuntimeValue::Bool(true),
8507 RuntimeValue::Char('z'),
8508 RuntimeValue::Nothing,
8509 RuntimeValue::Duration(10),
8510 RuntimeValue::Date(19_000),
8511 RuntimeValue::Moment(123),
8512 RuntimeValue::Span { months: 3, days: 14 },
8513 RuntimeValue::Time(99),
8514 ] {
8515 assert_roundtrips(&v);
8516 }
8517 }
8518
8519 #[test]
8520 fn text_roundtrips() {
8521 let v = RuntimeValue::Text(Rc::new("hello".to_string()));
8522 let p = assert_roundtrips(&v);
8523 assert_eq!(p, RtPayload::Text("hello".to_string()));
8524 }
8525
8526 #[test]
8527 fn peer_handle_roundtrips_exactly() {
8528 let v = RuntimeValue::Peer(Rc::new("ws://127.0.0.1:9944".to_string()));
8529 let p = assert_roundtrips(&v);
8530 assert_eq!(p, RtPayload::Peer("ws://127.0.0.1:9944".to_string()));
8531 assert!(matches!(rebuild(p), RuntimeValue::Peer(t) if t.as_str() == "ws://127.0.0.1:9944"));
8533 }
8534
8535 #[test]
8536 fn int_list_roundtrips() {
8537 let v = RuntimeValue::List(Rc::new(RefCell::new(ListRepr::from_values(vec![
8538 RuntimeValue::Int(1),
8539 RuntimeValue::Int(2),
8540 RuntimeValue::Int(3),
8541 ]))));
8542 let p = assert_roundtrips(&v);
8543 assert_eq!(p, RtPayload::List(vec![RtPayload::Int(1), RtPayload::Int(2), RtPayload::Int(3)]));
8544 }
8545
8546 #[test]
8547 fn set_and_tuple_roundtrip() {
8548 let set = RuntimeValue::Set(Rc::new(RefCell::new(vec![RuntimeValue::Int(7), RuntimeValue::Int(8)])));
8549 let p = assert_roundtrips(&set);
8550 assert_eq!(p, RtPayload::Set(vec![RtPayload::Int(7), RtPayload::Int(8)]));
8551
8552 let tup = RuntimeValue::Tuple(Rc::new(vec![RuntimeValue::Int(1), RuntimeValue::Bool(false), RuntimeValue::Char('x')]));
8553 let p = assert_roundtrips(&tup);
8554 assert_eq!(p, RtPayload::Tuple(vec![RtPayload::Int(1), RtPayload::Bool(false), RtPayload::Char('x')]));
8555 }
8556
8557 #[test]
8558 fn sets_are_canonical_regardless_of_insertion_order() {
8559 let mk = |order: &[i64]| {
8563 RuntimeValue::Set(Rc::new(RefCell::new(
8564 order.iter().map(|&n| RuntimeValue::Int(n)).collect::<Vec<_>>(),
8565 )))
8566 };
8567 let mut e1 = Vec::new();
8568 native_encode(&mk(&[5, 1, 3, 2, 4]), &mut e1).unwrap();
8569 let mut e2 = Vec::new();
8570 native_encode(&mk(&[4, 2, 3, 1, 5]), &mut e2).unwrap();
8571 let mut e3 = Vec::new();
8572 native_encode(&mk(&[1, 2, 3, 4, 5]), &mut e3).unwrap();
8573 assert_eq!(e1, e2, "same set, different insertion order → byte-identical wire");
8574 assert_eq!(e1, e3, "...identical to the already-sorted insertion order too");
8575
8576 let mut pos = 0;
8577 match native_decode(&e1, &mut pos).expect("decode") {
8578 RuntimeValue::Set(s) => {
8579 let mut got: Vec<i64> = s
8580 .borrow()
8581 .iter()
8582 .map(|v| match v {
8583 RuntimeValue::Int(n) => *n,
8584 other => panic!("expected Int in set, got {other:?}"),
8585 })
8586 .collect();
8587 got.sort_unstable();
8588 assert_eq!(got, vec![1, 2, 3, 4, 5], "canonical bytes round-trip to the same members");
8589 }
8590 other => panic!("expected a Set, got {other:?}"),
8591 }
8592 }
8593
8594 #[test]
8595 fn int_set_crushes_to_a_compressed_column() {
8596 let n = 1000i64;
8601 let order: Vec<RuntimeValue> = (1..=n).rev().map(RuntimeValue::Int).collect();
8602 let set = RuntimeValue::Set(Rc::new(RefCell::new(order)));
8603 let mut enc = Vec::new();
8604 native_encode(&set, &mut enc).unwrap();
8605 assert!(
8606 enc.len() < 64,
8607 "a consecutive int set of {n} must collapse to a closed-form column, got {} bytes",
8608 enc.len()
8609 );
8610 let mut pos = 0;
8611 match native_decode(&enc, &mut pos).unwrap() {
8612 RuntimeValue::Set(s) => {
8613 let mut got: Vec<i64> = s
8614 .borrow()
8615 .iter()
8616 .map(|v| match v {
8617 RuntimeValue::Int(k) => *k,
8618 other => panic!("expected Int, got {other:?}"),
8619 })
8620 .collect();
8621 got.sort_unstable();
8622 assert_eq!(got, (1..=n).collect::<Vec<_>>(), "round-trips to the full set");
8623 }
8624 other => panic!("expected a Set, got {other:?}"),
8625 }
8626 }
8627
8628 #[test]
8629 fn int_keyed_map_columnarizes_keys_and_values() {
8630 let n = 1000i64;
8637 let build = |rev: bool| {
8638 let mut keys: Vec<i64> = (0..n).collect();
8639 if rev {
8640 keys.reverse();
8641 }
8642 let mut m = MapStorage::default();
8643 for k in keys {
8644 m.insert(RuntimeValue::Int(k), RuntimeValue::Int(k * 2));
8645 }
8646 RuntimeValue::Map(Rc::new(RefCell::new(m)))
8647 };
8648
8649 let mut enc = Vec::new();
8650 native_encode(&build(false), &mut enc).unwrap();
8651 assert!(
8652 enc.len() < 64,
8653 "an affine int→int map of {n} entries must collapse BOTH columns to closed forms, got {} bytes",
8654 enc.len()
8655 );
8656
8657 let mut enc_rev = Vec::new();
8659 native_encode(&build(true), &mut enc_rev).unwrap();
8660 assert_eq!(enc, enc_rev, "int-keyed map encoding must be insertion-order-invariant");
8661
8662 let mut pos = 0;
8664 match native_decode(&enc, &mut pos).unwrap() {
8665 RuntimeValue::Map(m) => {
8666 let b = m.borrow();
8667 assert_eq!(b.len(), n as usize, "all entries recovered");
8668 for k in 0..n {
8669 let got = b.get(&RuntimeValue::Int(k)).expect("key present");
8670 assert_eq!(*got, RuntimeValue::Int(k * 2), "value for key {k} survived");
8671 }
8672 }
8673 other => panic!("expected a Map, got {other:?}"),
8674 }
8675 }
8676
8677 #[test]
8678 fn int_keyed_map_with_non_int_values_still_columnarizes_keys() {
8679 let build = |rev: bool| {
8682 let mut ks: Vec<i64> = vec![10, 20, 30, 40];
8683 if rev {
8684 ks.reverse();
8685 }
8686 let mut m = MapStorage::default();
8687 for k in ks {
8688 m.insert(RuntimeValue::Int(k), RuntimeValue::Text(Rc::new(format!("item_{k}"))));
8689 }
8690 RuntimeValue::Map(Rc::new(RefCell::new(m)))
8691 };
8692 let mut a = Vec::new();
8693 native_encode(&build(false), &mut a).unwrap();
8694 let mut b = Vec::new();
8695 native_encode(&build(true), &mut b).unwrap();
8696 assert_eq!(a, b, "int-keyed map with text values must be insertion-order-invariant");
8697 let mut pos = 0;
8698 match native_decode(&a, &mut pos).unwrap() {
8699 RuntimeValue::Map(m) => {
8700 let mb = m.borrow();
8701 assert_eq!(mb.len(), 4);
8702 for k in [10i64, 20, 30, 40] {
8703 let got = mb.get(&RuntimeValue::Int(k)).expect("key present");
8704 assert_eq!(*got, RuntimeValue::Text(Rc::new(format!("item_{k}"))));
8705 }
8706 }
8707 other => panic!("expected a Map, got {other:?}"),
8708 }
8709 }
8710
8711 #[test]
8712 fn int_keyed_map_front_codes_string_value_column() {
8713 let n = 100i64;
8718 let build = |rev: bool| {
8719 let mut ks: Vec<i64> = (0..n).collect();
8720 if rev {
8721 ks.reverse();
8722 }
8723 let mut m = MapStorage::default();
8724 for k in ks {
8725 m.insert(
8726 RuntimeValue::Int(k),
8727 RuntimeValue::Text(Rc::new(format!("https://example.com/items/{k}"))),
8728 );
8729 }
8730 RuntimeValue::Map(Rc::new(RefCell::new(m)))
8731 };
8732
8733 let mut enc = Vec::new();
8734 native_encode(&build(false), &mut enc).unwrap();
8735 assert!(
8738 enc.len() < 1200,
8739 "an int→string map with a shared value prefix must front-code its value column, got {} bytes",
8740 enc.len()
8741 );
8742
8743 let mut enc_rev = Vec::new();
8744 native_encode(&build(true), &mut enc_rev).unwrap();
8745 assert_eq!(enc, enc_rev, "int→string map must be insertion-order-invariant");
8746
8747 let mut pos = 0;
8748 match native_decode(&enc, &mut pos).unwrap() {
8749 RuntimeValue::Map(m) => {
8750 let b = m.borrow();
8751 assert_eq!(b.len(), n as usize);
8752 for k in 0..n {
8753 let got = b.get(&RuntimeValue::Int(k)).expect("key present");
8754 assert_eq!(
8755 *got,
8756 RuntimeValue::Text(Rc::new(format!("https://example.com/items/{k}"))),
8757 "value for key {k} survived"
8758 );
8759 }
8760 }
8761 other => panic!("expected a Map, got {other:?}"),
8762 }
8763 }
8764
8765 #[test]
8766 fn int_keyed_map_columnarizes_struct_value_column() {
8767 let n = 100i64;
8772 let rec = |id: i64| {
8773 let mut f = HashMap::new();
8774 f.insert("id".to_string(), RuntimeValue::Int(id));
8775 f.insert("name".to_string(), RuntimeValue::Text(Rc::new(format!("user_{id}"))));
8776 f.insert("active".to_string(), RuntimeValue::Bool(id % 2 == 0));
8777 RuntimeValue::Struct(Box::new(StructValue { type_name: "Rec".to_string(), fields: f }))
8778 };
8779 let build = |rev: bool| {
8780 let mut ks: Vec<i64> = (0..n).collect();
8781 if rev {
8782 ks.reverse();
8783 }
8784 let mut m = MapStorage::default();
8785 for k in ks {
8786 m.insert(RuntimeValue::Int(k), rec(k));
8787 }
8788 RuntimeValue::Map(Rc::new(RefCell::new(m)))
8789 };
8790
8791 let mut enc = Vec::new();
8792 native_encode(&build(false), &mut enc).unwrap();
8793 assert!(
8796 enc.len() < 1500,
8797 "an int→struct map must pack its value column columnarly (schema once), got {} bytes",
8798 enc.len()
8799 );
8800
8801 let mut enc_rev = Vec::new();
8802 native_encode(&build(true), &mut enc_rev).unwrap();
8803 assert_eq!(enc, enc_rev, "int→struct map must be insertion-order-invariant");
8804
8805 let mut pos = 0;
8810 let decoded = native_decode(&enc, &mut pos).unwrap();
8811 match &decoded {
8812 RuntimeValue::Map(m) => assert_eq!(m.borrow().len(), n as usize, "all rows recovered"),
8813 other => panic!("expected a Map, got {other:?}"),
8814 }
8815 let mut reenc = Vec::new();
8816 native_encode(&decoded, &mut reenc).unwrap();
8817 assert_eq!(reenc, enc, "decoded int→struct map must re-encode byte-identically");
8818 }
8819
8820 #[test]
8821 fn string_set_front_codes_shared_prefixes() {
8822 let words = ["user_1000", "user_1001", "user_1002", "user_1003", "user_2000"];
8826 let mk = |order: &[usize]| {
8827 RuntimeValue::Set(Rc::new(RefCell::new(
8828 order
8829 .iter()
8830 .map(|&i| RuntimeValue::Text(Rc::new(words[i].to_string())))
8831 .collect::<Vec<_>>(),
8832 )))
8833 };
8834 let mut e1 = Vec::new();
8835 native_encode(&mk(&[0, 1, 2, 3, 4]), &mut e1).unwrap();
8836 let mut e2 = Vec::new();
8837 native_encode(&mk(&[4, 2, 0, 3, 1]), &mut e2).unwrap();
8838 assert_eq!(e1, e2, "same string set, different insertion order → identical wire");
8839
8840 let naive: usize = words.iter().map(|w| w.len()).sum();
8841 assert!(
8842 e1.len() < naive,
8843 "front-coding must beat the {naive}-byte naive concat (shared prefixes elided), got {}",
8844 e1.len()
8845 );
8846
8847 let mut pos = 0;
8848 match native_decode(&e1, &mut pos).unwrap() {
8849 RuntimeValue::Set(s) => {
8850 let mut got: Vec<String> = s
8851 .borrow()
8852 .iter()
8853 .map(|v| match v {
8854 RuntimeValue::Text(t) => (**t).clone(),
8855 other => panic!("expected Text, got {other:?}"),
8856 })
8857 .collect();
8858 got.sort();
8859 let mut want: Vec<String> = words.iter().map(|w| w.to_string()).collect();
8860 want.sort();
8861 assert_eq!(got, want, "round-trips to the same members");
8862 }
8863 other => panic!("expected a Set, got {other:?}"),
8864 }
8865 }
8866
8867 #[test]
8868 fn single_entry_map_roundtrips_exactly() {
8869 let mut m: MapStorage = MapStorage::default();
8870 m.insert(RuntimeValue::Int(1), RuntimeValue::Text(Rc::new("a".to_string())));
8871 let v = RuntimeValue::Map(Rc::new(RefCell::new(m)));
8872 let p = assert_roundtrips(&v);
8873 assert_eq!(p, RtPayload::Map(vec![(RtPayload::Int(1), RtPayload::Text("a".to_string()))]));
8874 }
8875
8876 #[test]
8877 fn multi_entry_map_preserves_entries() {
8878 let mut m: MapStorage = MapStorage::default();
8879 m.insert(RuntimeValue::Int(1), RuntimeValue::Int(10));
8880 m.insert(RuntimeValue::Int(2), RuntimeValue::Int(20));
8881 let v = RuntimeValue::Map(Rc::new(RefCell::new(m)));
8882 let p = materialize(&v).unwrap();
8883 let entries = match &p {
8884 RtPayload::Map(e) => e,
8885 _ => panic!("expected map"),
8886 };
8887 assert_eq!(entries.len(), 2);
8888 assert!(entries.contains(&(RtPayload::Int(1), RtPayload::Int(10))));
8889 assert!(entries.contains(&(RtPayload::Int(2), RtPayload::Int(20))));
8890
8891 let p2 = materialize(&rebuild(p.clone())).unwrap();
8893 let e2 = match &p2 {
8894 RtPayload::Map(e) => e,
8895 _ => panic!("expected map"),
8896 };
8897 assert_eq!(entries.len(), e2.len());
8898 for e in entries {
8899 assert!(e2.contains(e), "entry {e:?} lost in round-trip");
8900 }
8901 }
8902
8903 #[test]
8904 fn single_field_struct_roundtrips_exactly() {
8905 let mut fields = HashMap::new();
8906 fields.insert("x".to_string(), RuntimeValue::Int(7));
8907 let v = RuntimeValue::Struct(Box::new(StructValue { type_name: "Point".to_string(), fields }));
8908 let p = assert_roundtrips(&v);
8909 assert_eq!(
8910 p,
8911 RtPayload::Struct {
8912 type_name: "Point".to_string(),
8913 fields: vec![("x".to_string(), RtPayload::Int(7))],
8914 }
8915 );
8916 }
8917
8918 #[test]
8919 fn inductive_roundtrips() {
8920 let v = RuntimeValue::Inductive(Box::new(InductiveValue {
8921 inductive_type: "Option".to_string(),
8922 constructor: "Some".to_string(),
8923 args: vec![RuntimeValue::Int(42)],
8924 }));
8925 let p = assert_roundtrips(&v);
8926 assert_eq!(
8927 p,
8928 RtPayload::Inductive {
8929 type_name: "Option".to_string(),
8930 constructor: "Some".to_string(),
8931 args: vec![RtPayload::Int(42)],
8932 }
8933 );
8934 }
8935
8936 #[test]
8937 fn nested_collections_roundtrip() {
8938 let v = RuntimeValue::List(Rc::new(RefCell::new(ListRepr::from_values(vec![
8939 RuntimeValue::Tuple(Rc::new(vec![RuntimeValue::Int(1), RuntimeValue::Bool(true)])),
8940 RuntimeValue::Text(Rc::new("nested".to_string())),
8941 ]))));
8942 assert_roundtrips(&v);
8943 }
8944
8945 use logicaffeine_data::wire::{self, WireDecode, WireEncode};
8949
8950 #[derive(Debug, Clone, PartialEq)]
8952 enum CE {
8953 CInt(i64),
8954 CText(String),
8955 CBool(bool),
8956 CBinOp { op: String, left: Box<CE>, right: Box<CE> },
8957 CList(Vec<CE>),
8958 }
8959 impl WireEncode for CE {
8960 fn wire_encode(&self, out: &mut Vec<u8>) {
8961 match self {
8962 CE::CInt(v) => { wire::write_inductive_header(out, "CE", "CInt", 1); v.wire_encode(out); }
8963 CE::CText(s) => { wire::write_inductive_header(out, "CE", "CText", 1); s.wire_encode(out); }
8964 CE::CBool(b) => { wire::write_inductive_header(out, "CE", "CBool", 1); b.wire_encode(out); }
8965 CE::CBinOp { op, left, right } => {
8966 wire::write_inductive_header(out, "CE", "CBinOp", 3);
8967 op.wire_encode(out);
8968 left.wire_encode(out);
8969 right.wire_encode(out);
8970 }
8971 CE::CList(xs) => { wire::write_inductive_header(out, "CE", "CList", 1); xs.wire_encode(out); }
8972 }
8973 }
8974 }
8975 impl WireDecode for CE {
8976 fn wire_decode(buf: &[u8], pos: &mut usize) -> Option<Self> {
8977 let (ty, ctor, _n) = wire::read_inductive_header(buf, pos)?;
8978 debug_assert_eq!(ty, "CE");
8979 Some(match ctor.as_str() {
8980 "CInt" => CE::CInt(i64::wire_decode(buf, pos)?),
8981 "CText" => CE::CText(String::wire_decode(buf, pos)?),
8982 "CBool" => CE::CBool(bool::wire_decode(buf, pos)?),
8983 "CBinOp" => CE::CBinOp {
8984 op: String::wire_decode(buf, pos)?,
8985 left: Box::<CE>::wire_decode(buf, pos)?,
8986 right: Box::<CE>::wire_decode(buf, pos)?,
8987 },
8988 "CList" => CE::CList(Vec::<CE>::wire_decode(buf, pos)?),
8989 _ => return None,
8990 })
8991 }
8992 }
8993
8994 fn ce_tree() -> CE {
8996 CE::CBinOp {
8997 op: "+".to_string(),
8998 left: Box::new(CE::CInt(2)),
8999 right: Box::new(CE::CList(vec![CE::CInt(3), CE::CBool(true), CE::CText("hi".to_string())])),
9000 }
9001 }
9002 fn rt_ind(ty: &str, ctor: &str, args: Vec<RuntimeValue>) -> RuntimeValue {
9003 RuntimeValue::Inductive(Box::new(InductiveValue {
9004 inductive_type: ty.to_string(),
9005 constructor: ctor.to_string(),
9006 args,
9007 }))
9008 }
9009 fn rt_tree() -> RuntimeValue {
9010 rt_ind("CE", "CBinOp", vec![
9011 RuntimeValue::Text(Rc::new("+".to_string())),
9012 rt_ind("CE", "CInt", vec![RuntimeValue::Int(2)]),
9013 rt_ind("CE", "CList", vec![RuntimeValue::List(Rc::new(RefCell::new(ListRepr::from_values(vec![
9014 rt_ind("CE", "CInt", vec![RuntimeValue::Int(3)]),
9015 rt_ind("CE", "CBool", vec![RuntimeValue::Bool(true)]),
9016 rt_ind("CE", "CText", vec![RuntimeValue::Text(Rc::new("hi".to_string()))]),
9017 ]))))]),
9018 ])
9019 }
9020
9021 #[test]
9022 fn peer_and_wire_core_produce_identical_bytes() {
9023 let peer_bytes = encode_value_raw(&rt_tree()).expect("peer encode");
9024 let mut wire_bytes = Vec::new();
9025 ce_tree().wire_encode(&mut wire_bytes);
9026 assert_eq!(
9027 peer_bytes, wire_bytes,
9028 "the shared wire core must be byte-identical to the peer codec"
9029 );
9030 }
9031
9032 #[test]
9033 fn peer_encode_then_wire_decode_reconstructs_the_generated_type() {
9034 let bytes = encode_value_raw(&rt_tree()).expect("peer encode");
9036 let mut pos = 0usize;
9037 let decoded = CE::wire_decode(&bytes, &mut pos).expect("wire decode");
9038 assert_eq!(pos, bytes.len(), "must consume every byte");
9039 assert_eq!(decoded, ce_tree());
9040 }
9041
9042 #[test]
9043 fn wire_encode_then_peer_decode_reconstructs_the_runtime_value() {
9044 let mut bytes = Vec::new();
9046 ce_tree().wire_encode(&mut bytes);
9047 let rv = decode_value_raw(&bytes).expect("peer decode");
9048 assert_eq!(materialize(&rv).unwrap(), materialize(&rt_tree()).unwrap());
9049 }
9050
9051 #[test]
9052 fn function_is_not_sendable() {
9053 let v = RuntimeValue::Function(Box::new(ClosureValue {
9054 body_index: 0,
9055 captured_env: HashMap::default(),
9056 param_names: vec![],
9057 generated: None,
9058 }));
9059 assert_eq!(materialize(&v), Err(MarshalError::NotSendable("Function")));
9060 }
9061
9062 fn assert_wire_roundtrips(v: &RuntimeValue, from: &str) {
9069 let bytes = message_to_wire(from, v).expect("message_to_wire");
9070 let (got_from, back) = message_from_wire(&bytes).expect("message_from_wire");
9071 assert_eq!(got_from, from, "sender lost on the wire");
9072 assert_eq!(
9073 materialize(v).expect("before"),
9074 materialize(&back).expect("after"),
9075 "wire round-trip changed the value"
9076 );
9077 }
9078
9079 #[test]
9080 fn message_wire_scalars_roundtrip() {
9081 for v in [
9082 RuntimeValue::Int(42),
9083 RuntimeValue::Float(2.5),
9084 RuntimeValue::Bool(true),
9085 RuntimeValue::Char('z'),
9086 RuntimeValue::Text(Rc::new("ping".to_string())),
9087 RuntimeValue::Nothing,
9088 RuntimeValue::Duration(1000),
9089 ] {
9090 assert_wire_roundtrips(&v, "alice");
9091 }
9092 }
9093
9094 #[test]
9095 fn message_wire_is_compact_binary() {
9096 let items: Vec<RuntimeValue> = (0..100).map(RuntimeValue::Int).collect();
9099 let v = RuntimeValue::List(Rc::new(RefCell::new(ListRepr::from_values(items))));
9100 let bytes = message_to_wire("", &v).unwrap();
9101 assert!(bytes.len() < 100 * 12, "wire should be compact, was {} bytes", bytes.len());
9102 assert_wire_roundtrips(&v, "");
9103 }
9104
9105 #[test]
9106 fn message_wire_anonymous_sender_is_empty_from() {
9107 let bytes = message_to_wire("", &RuntimeValue::Int(1)).unwrap();
9108 let (from, _) = message_from_wire(&bytes).unwrap();
9109 assert_eq!(from, "");
9110 }
9111
9112 #[test]
9113 fn message_wire_list_and_tuple_and_set_roundtrip() {
9114 let list = RuntimeValue::List(Rc::new(RefCell::new(ListRepr::from_values(vec![
9115 RuntimeValue::Int(1),
9116 RuntimeValue::Text(Rc::new("two".to_string())),
9117 RuntimeValue::Bool(true),
9118 ]))));
9119 assert_wire_roundtrips(&list, "");
9120
9121 let tup = RuntimeValue::Tuple(Rc::new(vec![RuntimeValue::Int(1), RuntimeValue::Char('q')]));
9122 assert_wire_roundtrips(&tup, "");
9123
9124 let set = RuntimeValue::Set(Rc::new(RefCell::new(vec![RuntimeValue::Int(7), RuntimeValue::Int(8)])));
9125 assert_wire_roundtrips(&set, "");
9126 }
9127
9128 #[test]
9129 fn message_wire_single_entry_map_roundtrips() {
9130 let mut m: MapStorage = MapStorage::default();
9131 m.insert(RuntimeValue::Text(Rc::new("k".to_string())), RuntimeValue::Int(9));
9132 let v = RuntimeValue::Map(Rc::new(RefCell::new(m)));
9133 assert_wire_roundtrips(&v, "");
9134 }
9135
9136 #[test]
9137 fn message_wire_struct_roundtrips_by_field() {
9138 let mut fields = HashMap::new();
9139 fields.insert("x".to_string(), RuntimeValue::Int(1));
9140 fields.insert("y".to_string(), RuntimeValue::Int(2));
9141 let v = RuntimeValue::Struct(Box::new(StructValue { type_name: "Point".to_string(), fields }));
9142 let bytes = message_to_wire("alice", &v).unwrap();
9143 let (_from, back) = message_from_wire(&bytes).unwrap();
9144 match back {
9145 RuntimeValue::Struct(s) => {
9146 assert_eq!(s.type_name, "Point");
9147 assert_eq!(s.fields.get("x"), Some(&RuntimeValue::Int(1)));
9148 assert_eq!(s.fields.get("y"), Some(&RuntimeValue::Int(2)));
9149 }
9150 other => panic!("expected a struct, got {other:?}"),
9151 }
9152 }
9153
9154 #[test]
9155 fn message_wire_inductive_roundtrips() {
9156 let v = RuntimeValue::Inductive(Box::new(InductiveValue {
9157 inductive_type: "Option".to_string(),
9158 constructor: "Some".to_string(),
9159 args: vec![RuntimeValue::Int(42)],
9160 }));
9161 assert_wire_roundtrips(&v, "");
9162 }
9163
9164 #[test]
9165 fn message_wire_nested_list_of_structs_roundtrips() {
9166 let mut fields = HashMap::new();
9167 fields.insert("n".to_string(), RuntimeValue::Int(1));
9168 let s = RuntimeValue::Struct(Box::new(StructValue { type_name: "Item".to_string(), fields }));
9169 let v = RuntimeValue::List(Rc::new(RefCell::new(ListRepr::from_values(vec![
9170 s,
9171 RuntimeValue::Tuple(Rc::new(vec![RuntimeValue::Int(3), RuntimeValue::Bool(false)])),
9172 ]))));
9173 assert_wire_roundtrips(&v, "carol");
9174 }
9175
9176 #[test]
9177 fn message_wire_channel_handle_is_not_network_portable() {
9178 let v = RuntimeValue::Chan(logicaffeine_runtime::ChanId(3));
9180 let err = message_to_wire("", &v).expect_err("a channel must not be sendable over the network");
9181 assert!(err.contains("channel") || err.contains("task"), "got: {err}");
9182 }
9183
9184 #[test]
9185 fn message_wire_function_is_rejected_with_a_clear_error() {
9186 let v = RuntimeValue::Function(Box::new(ClosureValue {
9187 body_index: 0,
9188 captured_env: HashMap::default(),
9189 param_names: vec![],
9190 generated: None,
9191 }));
9192 let err = message_to_wire("", &v).expect_err("a closure must not be sendable");
9193 assert!(err.contains("Function"), "got: {err}");
9194 }
9195
9196 #[test]
9197 fn message_wire_malformed_bytes_decode_to_none() {
9198 assert!(message_from_wire(b"").is_none()); assert!(message_from_wire(b"\xff\xff\xff\xff garbage").is_none()); let good = message_to_wire("alice", &RuntimeValue::Text(Rc::new("hi".to_string()))).unwrap();
9202 assert!(message_from_wire(&good[..good.len() / 2]).is_none());
9203 }
9204
9205 fn assert_wire_stable(v: &RuntimeValue) {
9216 let once = message_to_wire("peer", v).expect("encode");
9217 let (from, back) = message_from_wire(&once).expect("decode");
9218 assert_eq!(from, "peer", "sender lost");
9219 let twice = message_to_wire("peer", &back).expect("re-encode");
9220 assert_eq!(once, twice, "round-trip was not byte-stable for {v:?}");
9221 }
9222
9223 #[test]
9224 fn wire_boundary_ints_roundtrip() {
9225 for n in [0i64, 1, -1, i64::MIN, i64::MAX, i64::MIN + 1, i64::MAX - 1, i32::MIN as i64, i32::MAX as i64] {
9226 assert_wire_stable(&RuntimeValue::Int(n));
9227 }
9228 }
9229
9230 #[test]
9231 fn wire_special_floats_roundtrip_bit_exact() {
9232 for f in [
9233 0.0f64, -0.0, 1.0, -1.0, f64::INFINITY, f64::NEG_INFINITY, f64::NAN,
9234 f64::MIN, f64::MAX, f64::MIN_POSITIVE, 1e-308, -1e308, std::f64::consts::PI,
9235 ] {
9236 let bytes = message_to_wire("", &RuntimeValue::Float(f)).unwrap();
9237 let (_, back) = message_from_wire(&bytes).unwrap();
9238 let RuntimeValue::Float(g) = back else { panic!("not a float") };
9239 assert_eq!(f.to_bits(), g.to_bits(), "float {f} lost bits");
9240 }
9241 }
9242
9243 #[test]
9244 fn wire_unicode_text_and_char_roundtrip() {
9245 for s in ["", "ascii", "héllo", "日本語", "emoji 😀🎉", "null\0byte", "tabs\tand\nnewlines"] {
9246 assert_wire_stable(&RuntimeValue::Text(Rc::new(s.to_string())));
9247 }
9248 for c in ['a', '\0', '😀', '\u{10FFFF}', 'λ', '\n', '\u{1}'] {
9249 assert_wire_stable(&RuntimeValue::Char(c));
9250 }
9251 }
9252
9253 #[test]
9254 fn wire_empty_collections_roundtrip() {
9255 assert_wire_stable(&RuntimeValue::List(Rc::new(RefCell::new(ListRepr::from_values(vec![])))));
9256 assert_wire_stable(&RuntimeValue::Tuple(Rc::new(vec![])));
9257 assert_wire_stable(&RuntimeValue::Set(Rc::new(RefCell::new(vec![]))));
9258 assert_wire_stable(&RuntimeValue::Map(Rc::new(RefCell::new(MapStorage::default()))));
9259 assert_wire_stable(&RuntimeValue::Struct(Box::new(StructValue {
9260 type_name: "Empty".to_string(),
9261 fields: HashMap::new(),
9262 })));
9263 assert_wire_stable(&RuntimeValue::Inductive(Box::new(InductiveValue {
9264 inductive_type: "Unit".to_string(),
9265 constructor: "Unit".to_string(),
9266 args: vec![],
9267 })));
9268 }
9269
9270 #[test]
9271 fn wire_temporal_and_misc_scalars_roundtrip() {
9272 for v in [
9273 RuntimeValue::Nothing,
9274 RuntimeValue::Bool(true),
9275 RuntimeValue::Bool(false),
9276 RuntimeValue::Duration(i64::MAX),
9277 RuntimeValue::Date(i32::MIN),
9278 RuntimeValue::Moment(-1),
9279 RuntimeValue::Span { months: i32::MAX, days: i32::MIN },
9280 RuntimeValue::Time(0),
9281 RuntimeValue::Peer(Rc::new("ws://host:9944".to_string())),
9282 ] {
9283 assert_wire_stable(&v);
9284 }
9285 }
9286
9287 #[test]
9288 fn wire_struct_field_order_is_canonical() {
9289 let mut a = HashMap::new();
9291 a.insert("z".to_string(), RuntimeValue::Int(1));
9292 a.insert("a".to_string(), RuntimeValue::Int(2));
9293 a.insert("m".to_string(), RuntimeValue::Int(3));
9294 let mut b = HashMap::new();
9295 b.insert("m".to_string(), RuntimeValue::Int(3));
9296 b.insert("z".to_string(), RuntimeValue::Int(1));
9297 b.insert("a".to_string(), RuntimeValue::Int(2));
9298 let va = RuntimeValue::Struct(Box::new(StructValue { type_name: "S".into(), fields: a }));
9299 let vb = RuntimeValue::Struct(Box::new(StructValue { type_name: "S".into(), fields: b }));
9300 assert_eq!(
9301 message_to_wire("x", &va).unwrap(),
9302 message_to_wire("x", &vb).unwrap(),
9303 "struct encoding must be canonical (field order independent)"
9304 );
9305 }
9306
9307 #[test]
9308 fn wire_map_entry_order_is_canonical() {
9309 let mut a = MapStorage::default();
9310 a.insert(RuntimeValue::Int(3), RuntimeValue::Int(30));
9311 a.insert(RuntimeValue::Int(1), RuntimeValue::Int(10));
9312 a.insert(RuntimeValue::Int(2), RuntimeValue::Int(20));
9313 let mut b = MapStorage::default();
9314 b.insert(RuntimeValue::Int(1), RuntimeValue::Int(10));
9315 b.insert(RuntimeValue::Int(2), RuntimeValue::Int(20));
9316 b.insert(RuntimeValue::Int(3), RuntimeValue::Int(30));
9317 let va = RuntimeValue::Map(Rc::new(RefCell::new(a)));
9318 let vb = RuntimeValue::Map(Rc::new(RefCell::new(b)));
9319 assert_eq!(
9320 message_to_wire("x", &va).unwrap(),
9321 message_to_wire("x", &vb).unwrap(),
9322 "map encoding must be canonical (entry order independent)"
9323 );
9324 }
9325
9326 #[test]
9327 fn wire_rejects_nonportable_buried_in_a_container() {
9328 let in_list = RuntimeValue::List(Rc::new(RefCell::new(ListRepr::from_values(vec![
9330 RuntimeValue::Int(1),
9331 RuntimeValue::Chan(logicaffeine_runtime::ChanId(5)),
9332 ]))));
9333 let err = message_to_wire("", &in_list).expect_err("buried channel must be rejected");
9334 assert!(err.contains("channel") || err.contains("task"), "got: {err}");
9335
9336 let mut m = MapStorage::default();
9338 m.insert(RuntimeValue::Int(1), RuntimeValue::TaskHandle(logicaffeine_runtime::TaskId(7)));
9339 let in_map = RuntimeValue::Map(Rc::new(RefCell::new(m)));
9340 assert!(message_to_wire("", &in_map).is_err(), "buried task handle must be rejected");
9341
9342 let mut fields = HashMap::new();
9344 fields.insert(
9345 "f".to_string(),
9346 RuntimeValue::Function(Box::new(ClosureValue {
9347 body_index: 0,
9348 captured_env: HashMap::default(),
9349 param_names: vec![],
9350 generated: None,
9351 })),
9352 );
9353 let in_struct = RuntimeValue::Struct(Box::new(StructValue { type_name: "Holder".into(), fields }));
9354 let err = message_to_wire("", &in_struct).expect_err("buried closure must be rejected");
9355 assert!(err.contains("Function"), "got: {err}");
9356 }
9357
9358 #[test]
9359 fn wire_checked_detects_corruption() {
9360 let v = RuntimeValue::Text(Rc::new("important".to_string()));
9361 let good = message_to_wire_with("a", &v, WireCodec::Native, WireIntegrity::Checked).unwrap();
9362 assert!(message_from_wire(&good).is_some(), "intact checked message decodes");
9363 let mut bad = good.clone();
9365 *bad.last_mut().unwrap() ^= 0xFF;
9366 assert!(message_from_wire(&bad).is_none(), "corruption must be rejected");
9367 let mut bad2 = good;
9369 bad2[1] ^= 0xFF;
9370 assert!(message_from_wire(&bad2).is_none(), "a mangled checksum must be rejected");
9371 }
9372
9373 #[test]
9374 fn wire_raw_skips_the_checksum_for_speed() {
9375 let v = RuntimeValue::Int(7);
9376 let raw = message_to_wire_with("", &v, WireCodec::Native, WireIntegrity::Raw).unwrap();
9377 let checked = message_to_wire_with("", &v, WireCodec::Native, WireIntegrity::Checked).unwrap();
9378 assert_eq!(checked.len(), raw.len() + 8, "checked adds exactly the 8-byte checksum");
9379 assert_eq!(message_from_wire(&raw).unwrap().1, RuntimeValue::Int(7));
9380 let mut tampered = raw;
9383 *tampered.last_mut().unwrap() ^= 0x01;
9384 let _ = message_from_wire(&tampered);
9385 }
9386
9387 #[test]
9388 fn wire_all_codec_and_integrity_modes_interoperate() {
9389 let v = RuntimeValue::Text(Rc::new("hello".to_string()));
9390 for codec in [WireCodec::Native, WireCodec::Json] {
9391 for integrity in [WireIntegrity::Raw, WireIntegrity::Checked] {
9392 let bytes = message_to_wire_with("s", &v, codec, integrity).unwrap();
9393 let (from, back) = message_from_wire(&bytes).expect("decodes any mode");
9394 assert_eq!(from, "s");
9395 assert_eq!(back, v, "{codec:?}/{integrity:?} did not round-trip");
9396 }
9397 }
9398 }
9399
9400 #[test]
9401 fn wire_compression_shrinks_redundant_payloads_and_roundtrips() {
9402 let v = RuntimeValue::List(Rc::new(RefCell::new(ListRepr::Boxed(
9404 (0..500).map(|_| RuntimeValue::Text(Rc::new("the same repeated string".to_string()))).collect(),
9405 ))));
9406 let plain = message_to_wire("", &v).unwrap();
9407 let zipped = with_compression(|| message_to_wire("", &v).unwrap());
9408 assert!(zipped.len() * 2 < plain.len(), "redundant data should compress: {} vs {}", zipped.len(), plain.len());
9409 let count = |b: &[u8]| match message_from_wire(b).unwrap().1 {
9411 RuntimeValue::List(l) => l.borrow().len(),
9412 other => panic!("expected a list, got {other:?}"),
9413 };
9414 assert_eq!(count(&zipped), 500);
9415 assert_eq!(count(&plain), 500);
9416 }
9417
9418 #[test]
9419 fn wire_compression_never_grows_a_message() {
9420 let v = RuntimeValue::Int(42);
9423 let plain = message_to_wire("", &v).unwrap();
9424 let maybe = with_compression(|| message_to_wire("", &v).unwrap());
9425 assert!(maybe.len() <= plain.len(), "compression must never grow a message");
9426 assert_eq!(message_from_wire(&maybe).unwrap().1, RuntimeValue::Int(42));
9427 }
9428
9429 #[test]
9430 fn wire_compressed_message_integrity_is_checked_before_inflate() {
9431 let v = RuntimeValue::List(Rc::new(RefCell::new(ListRepr::Boxed(
9432 (0..500).map(|_| RuntimeValue::Text(Rc::new("redundant".to_string()))).collect(),
9433 ))));
9434 let mut zipped =
9435 with_compression(|| message_to_wire_with("", &v, WireCodec::Native, WireIntegrity::Checked)).unwrap();
9436 assert!(message_from_wire(&zipped).is_some(), "intact compressed message decodes");
9437 *zipped.last_mut().unwrap() ^= 0xFF;
9440 assert!(message_from_wire(&zipped).is_none(), "corruption of a compressed message must be rejected");
9441 }
9442
9443 fn redundant_list(n: usize) -> RuntimeValue {
9444 RuntimeValue::List(Rc::new(RefCell::new(ListRepr::Boxed(
9445 (0..n).map(|_| RuntimeValue::Text(Rc::new("the same repeated string value".to_string()))).collect(),
9446 ))))
9447 }
9448 fn count_list(v: &RuntimeValue) -> usize {
9449 match v {
9450 RuntimeValue::List(l) => l.borrow().len(),
9451 other => panic!("expected a list, got {other:?}"),
9452 }
9453 }
9454
9455 #[test]
9456 fn wire_lz4_roundtrips_and_shrinks_redundant() {
9457 let v = redundant_list(500);
9458 let plain = message_to_wire("", &v).unwrap();
9459 let lz = with_compression_codec(WireCompression::Lz4, || message_to_wire("", &v).unwrap());
9460 assert!(lz.len() < plain.len(), "lz4 should shrink redundant data: {} vs {}", lz.len(), plain.len());
9461 assert_eq!(count_list(&message_from_wire(&lz).unwrap().1), 500);
9463 }
9464
9465 #[test]
9466 fn wire_compression_codec_is_self_describing() {
9467 let v = redundant_list(300);
9470 for c in [WireCompression::Deflate, WireCompression::Lz4] {
9471 let bytes = with_compression_codec(c, || message_to_wire("", &v).unwrap());
9472 assert_eq!(count_list(&message_from_wire(&bytes).unwrap().1), 300, "codec {c:?} self-describes");
9473 let (_, comp, _) = unframe(&bytes).unwrap();
9474 assert_eq!(comp, c, "header round-trips the codec id for {c:?}");
9475 }
9476 }
9477
9478 #[test]
9479 fn wire_old_deflate_bytes_still_decode() {
9480 let v = redundant_list(200);
9483 let body = {
9484 let mut out = Vec::new();
9485 write_str("", &mut out);
9486 native_encode(&v, &mut out).unwrap();
9487 miniz_oxide::deflate::compress_to_vec(&out, 6)
9488 };
9489 let mut legacy = vec![H_COMPRESSED]; legacy.extend_from_slice(&body);
9491 assert_eq!(count_list(&message_from_wire(&legacy).unwrap().1), 200);
9492 }
9493
9494 #[cfg(not(target_arch = "wasm32"))]
9495 #[test]
9496 fn wire_zstd_roundtrips_native_and_is_self_describing() {
9497 let v = redundant_list(500);
9498 let plain = message_to_wire("", &v).unwrap();
9499 let z = with_compression_codec(WireCompression::Zstd, || message_to_wire("", &v).unwrap());
9500 assert!(z.len() < plain.len(), "zstd should shrink redundant data: {} vs {}", z.len(), plain.len());
9501 assert_eq!(count_list(&message_from_wire(&z).unwrap().1), 500);
9502 let (_, comp, _) = unframe(&z).unwrap();
9503 assert_eq!(comp, WireCompression::Zstd, "header records zstd");
9504 }
9505
9506 #[cfg(not(target_arch = "wasm32"))]
9507 #[test]
9508 fn wire_zstd_decodes_via_ruzstd_parity() {
9509 let v = redundant_list(500);
9513 let z = with_compression_codec(WireCompression::Zstd, || message_to_wire("", &v).unwrap());
9514 let (_codec, comp, body) = unframe(&z).expect("unframe");
9515 assert_eq!(comp, WireCompression::Zstd);
9516 let via_c = zstd::decode_all(body).expect("C zstd decode");
9517 let via_ruzstd = zstd_decode_ruzstd(body).expect("ruzstd decode");
9518 assert_eq!(via_c, via_ruzstd, "ruzstd must match C zstd byte-for-byte");
9519 }
9520
9521 #[cfg(not(target_arch = "wasm32"))]
9522 #[test]
9523 fn wire_compression_level_dial_trades_size_and_roundtrips() {
9524 let v = RuntimeValue::List(Rc::new(RefCell::new(ListRepr::Boxed(
9527 (0..2000).map(|i| RuntimeValue::Text(Rc::new(format!("event-{i}-status-{}", i % 37)))).collect(),
9528 ))));
9529 let at = |lvl| {
9530 with_compression_level(lvl, || with_compression_codec(WireCompression::Zstd, || message_to_wire("", &v).unwrap()))
9531 };
9532 let fast = at(WireCompressionLevel::Fast);
9533 let bal = at(WireCompressionLevel::Balanced);
9534 let max = at(WireCompressionLevel::Max);
9535 assert!(max.len() <= bal.len() && bal.len() <= fast.len(), "max {} ≤ bal {} ≤ fast {}", max.len(), bal.len(), fast.len());
9536 for b in [&fast, &bal, &max] {
9537 assert!(message_from_wire(b).is_some(), "every level decodes");
9538 }
9539 let default = with_compression_codec(WireCompression::Zstd, || message_to_wire("", &v).unwrap());
9541 assert_eq!(default.len(), bal.len(), "default level is Balanced");
9542 }
9543
9544 #[cfg(not(target_arch = "wasm32"))]
9545 #[test]
9546 fn wire_zstd_ratio_beats_deflate_on_redundant() {
9547 let v = redundant_list(1000);
9548 let d = with_compression_codec(WireCompression::Deflate, || message_to_wire("", &v).unwrap());
9549 let z = with_compression_codec(WireCompression::Zstd, || message_to_wire("", &v).unwrap());
9550 assert!(z.len() <= d.len(), "zstd should match or beat deflate: zstd {} vs deflate {}", z.len(), d.len());
9551 }
9552
9553 fn point(x: i64, y: i64) -> RuntimeValue {
9554 let mut f = HashMap::new();
9555 f.insert("x".to_string(), RuntimeValue::Int(x));
9556 f.insert("y".to_string(), RuntimeValue::Int(y));
9557 RuntimeValue::Struct(Box::new(StructValue { type_name: "Point".to_string(), fields: f }))
9558 }
9559 fn struct_list(n: i64) -> RuntimeValue {
9560 RuntimeValue::List(Rc::new(RefCell::new(ListRepr::Boxed((0..n).map(|i| point(i, i * 2)).collect()))))
9561 }
9562 fn enum_val(ty: &str, ctor: &str, args: Vec<RuntimeValue>) -> RuntimeValue {
9563 RuntimeValue::Inductive(Box::new(InductiveValue {
9564 inductive_type: ty.to_string(),
9565 constructor: ctor.to_string(),
9566 args,
9567 }))
9568 }
9569
9570 fn assert_columnar_roundtrip(v: &RuntimeValue, expect_tag: u8) {
9575 let mut buf = Vec::new();
9576 native_encode(v, &mut buf).unwrap();
9577 assert_eq!(buf[0], expect_tag, "top wire tag");
9578 let mut pos = 0;
9579 let back = native_decode(&buf, &mut pos).unwrap();
9580 assert_eq!(pos, buf.len(), "decode consumes the whole buffer");
9581 let mut buf2 = Vec::new();
9582 native_encode(&back, &mut buf2).unwrap();
9583 assert_eq!(buf2, buf, "re-encode of the decoded value is byte-identical (exact rows, canonical)");
9584 }
9585
9586 #[test]
9587 fn wire_homogeneous_struct_list_packs_columnar() {
9588 assert_columnar_roundtrip(&struct_list(1000), T_STRUCTS);
9589 }
9590
9591 #[test]
9592 fn wire_columnar_struct_list_is_far_smaller_than_boxed() {
9593 let mut buf = Vec::new();
9597 native_encode(&struct_list(1000), &mut buf).unwrap();
9598 assert!(buf.len() < 6000, "columnar 1000×Point should be well under boxed's ~16 KB, was {}", buf.len());
9599 }
9600
9601 #[test]
9602 fn wire_columnar_int_field_is_memcpy_under_fixed() {
9603 let v = struct_list(200);
9607 let varint = {
9608 let mut b = Vec::new();
9609 native_encode(&v, &mut b).unwrap();
9610 b
9611 };
9612 let fixed = {
9613 let mut b = Vec::new();
9614 with_fixed_numerics(|| native_encode(&v, &mut b).unwrap());
9615 b
9616 };
9617 assert_eq!(varint[0], T_STRUCTS);
9618 assert_eq!(fixed[0], T_STRUCTS);
9619 assert!(fixed.len() > varint.len(), "fixed int columns are memcpy-wide: fixed {} vs varint {}", fixed.len(), varint.len());
9620 let mut pos = 0;
9622 let back = native_decode(&fixed, &mut pos).unwrap();
9623 let mut re = Vec::new();
9624 with_fixed_numerics(|| native_encode(&back, &mut re).unwrap());
9625 assert_eq!(re, fixed, "fixed columnar decodes to the exact rows");
9626 }
9627
9628 #[test]
9629 fn wire_ragged_struct_list_falls_back_to_boxed() {
9630 let a = point(1, 2);
9632 let mut bf = HashMap::new();
9633 bf.insert("x".to_string(), RuntimeValue::Int(3)); let b = RuntimeValue::Struct(Box::new(StructValue { type_name: "Point".to_string(), fields: bf }));
9635 let v = RuntimeValue::List(Rc::new(RefCell::new(ListRepr::Boxed(vec![a, b]))));
9636 assert_columnar_roundtrip(&v, T_LIST); }
9638
9639 #[test]
9640 fn wire_columnar_struct_roundtrip_is_byte_stable() {
9641 assert_wire_stable(&struct_list(50));
9642 }
9643
9644 #[test]
9645 fn wire_in_memory_columnar_structs_encode_identically_to_boxed() {
9646 let rows: Vec<RuntimeValue> = (0..100).map(|i| point(i, i * 2)).collect();
9650 let repr = ListRepr::from_values(rows.clone());
9651 assert!(matches!(repr, ListRepr::Structs { .. }), "from_values de-boxes a struct list to columns");
9652 let columnar = RuntimeValue::List(Rc::new(RefCell::new(repr)));
9653 let boxed = RuntimeValue::List(Rc::new(RefCell::new(ListRepr::Boxed(rows))));
9654 assert_eq!(
9655 message_to_wire("p", &columnar).unwrap(),
9656 message_to_wire("p", &boxed).unwrap(),
9657 "in-memory columns encode byte-identically to the boxed columnar path"
9658 );
9659 }
9660
9661 #[test]
9662 fn wire_struct_list_decodes_to_columnar_repr() {
9663 let bytes = message_to_wire("p", &struct_list(100)).unwrap();
9666 match message_from_wire(&bytes).unwrap().1 {
9667 RuntimeValue::List(l) => {
9668 assert!(matches!(&*l.borrow(), ListRepr::Structs { .. }), "decodes to the columnar Structs repr");
9669 assert_eq!(l.borrow().len(), 100);
9670 }
9671 other => panic!("expected a list, got {other:?}"),
9672 }
9673 }
9674
9675 #[test]
9676 fn wire_nullary_enum_list_packs_dictionary() {
9677 let names = ["Red", "Green", "Blue"];
9678 let v = RuntimeValue::List(Rc::new(RefCell::new(ListRepr::Boxed(
9679 (0..900).map(|i| enum_val("Color", names[i % 3], vec![])).collect(),
9680 ))));
9681 let mut buf = Vec::new();
9682 native_encode(&v, &mut buf).unwrap();
9683 assert!(buf.len() < 1200, "dictionaried enum list should be tiny, was {}", buf.len());
9684 assert_columnar_roundtrip(&v, T_INDUCTIVES);
9685 }
9686
9687 #[test]
9688 fn wire_arg_enum_list_packs_columnar() {
9689 let v = RuntimeValue::List(Rc::new(RefCell::new(ListRepr::Boxed(
9692 (0..10).map(|i| enum_val("Option", "Some", vec![RuntimeValue::Int(i)])).collect(),
9693 ))));
9694 assert_columnar_roundtrip(&v, T_INDUCTIVES);
9695 }
9696
9697 #[test]
9698 fn wire_mixed_arity_enum_list_packs_columnar() {
9699 let rows: Vec<RuntimeValue> = (0..20)
9701 .map(|i| {
9702 if i % 2 == 0 {
9703 enum_val("Option", "Some", vec![RuntimeValue::Int(i)])
9704 } else {
9705 enum_val("Option", "None", vec![])
9706 }
9707 })
9708 .collect();
9709 let v = RuntimeValue::List(Rc::new(RefCell::new(ListRepr::Boxed(rows))));
9710 assert_columnar_roundtrip(&v, T_INDUCTIVES);
9711 }
9712
9713 #[test]
9714 fn wire_enum_list_decodes_to_columnar_repr() {
9715 let rows: Vec<RuntimeValue> =
9717 (0..50).map(|i| enum_val("Option", "Some", vec![RuntimeValue::Int(i)])).collect();
9718 let bytes = message_to_wire("p", &RuntimeValue::List(Rc::new(RefCell::new(ListRepr::Boxed(rows))))).unwrap();
9719 match message_from_wire(&bytes).unwrap().1 {
9720 RuntimeValue::List(l) => {
9721 assert!(matches!(&*l.borrow(), ListRepr::Inductives { .. }), "decodes to the columnar Inductives repr");
9722 assert_eq!(l.borrow().len(), 50);
9723 }
9724 other => panic!("expected a list, got {other:?}"),
9725 }
9726 }
9727
9728 #[test]
9729 fn wire_schema_dictionary_sends_schema_once_and_shrinks() {
9730 let v = struct_list(50);
9733 let mut send_cache = WireSchemaCache::default();
9734 let mut recv_cache = WireSchemaCache::default();
9735 let m1 = message_to_wire_cached("p", &v, WireCodec::Native, WireIntegrity::Raw, &mut send_cache).unwrap();
9736 let m2 = message_to_wire_cached("p", &v, WireCodec::Native, WireIntegrity::Raw, &mut send_cache).unwrap();
9737 assert!(m2.len() < m1.len(), "the 2nd message references the schema and is smaller: {} vs {}", m2.len(), m1.len());
9738 let d1 = message_from_wire_cached(&m1, &mut recv_cache).unwrap().1;
9741 let d2 = message_from_wire_cached(&m2, &mut recv_cache).unwrap().1;
9742 let canon = |x: &RuntimeValue| message_to_wire("p", x).unwrap();
9743 assert_eq!(canon(&d1), canon(&v));
9744 assert_eq!(canon(&d2), canon(&v));
9745 }
9746
9747 #[test]
9748 fn wire_single_struct_schema_ref_drops_field_names_and_shrinks() {
9749 let v = point(1, 2);
9753 let mut sc = WireSchemaCache::default();
9754 let mut rc = WireSchemaCache::default();
9755 let m1 = message_to_wire_cached("p", &v, WireCodec::Native, WireIntegrity::Raw, &mut sc).unwrap();
9756 let m2 = message_to_wire_cached("p", &v, WireCodec::Native, WireIntegrity::Raw, &mut sc).unwrap();
9757 assert!(m2.len() < m1.len(), "2nd lone struct references the schema and is smaller: {} vs {}", m2.len(), m1.len());
9758 let canon = |x: &RuntimeValue| message_to_wire("p", x).unwrap();
9759 let d1 = message_from_wire_cached(&m1, &mut rc).unwrap().1;
9760 let d2 = message_from_wire_cached(&m2, &mut rc).unwrap().1;
9761 assert_eq!(canon(&d1), canon(&v));
9762 assert_eq!(canon(&d2), canon(&v));
9763 }
9764
9765 #[test]
9766 fn wire_single_struct_sequential_ref_beats_inline_field_names() {
9767 let v = point(7, 9);
9771 let inline = message_to_wire("p", &v).unwrap();
9772 let mut sc = WireSchemaCache::sequential();
9773 let _def = message_to_wire_cached("p", &v, WireCodec::Native, WireIntegrity::Raw, &mut sc).unwrap();
9774 let refmsg = message_to_wire_cached("p", &v, WireCodec::Native, WireIntegrity::Raw, &mut sc).unwrap();
9775 assert!(refmsg.len() < inline.len(), "schema-ref ({}) must beat inline field-names ({})", refmsg.len(), inline.len());
9776 }
9777
9778 #[test]
9779 fn wire_single_struct_def_decodes_without_a_cache() {
9780 let v = point(3, 4);
9783 let mut sc = WireSchemaCache::default();
9784 let m1 = message_to_wire_cached("p", &v, WireCodec::Native, WireIntegrity::Raw, &mut sc).unwrap();
9785 let d = message_from_wire(&m1).unwrap().1;
9786 assert_eq!(message_to_wire("p", &d).unwrap(), message_to_wire("p", &v).unwrap());
9787 }
9788
9789 #[test]
9790 fn wire_single_struct_ref_without_cache_fails_cleanly() {
9791 let v = point(5, 6);
9794 let mut sc = WireSchemaCache::default();
9795 let _m1 = message_to_wire_cached("p", &v, WireCodec::Native, WireIntegrity::Raw, &mut sc).unwrap();
9796 let m2 = message_to_wire_cached("p", &v, WireCodec::Native, WireIntegrity::Raw, &mut sc).unwrap();
9797 assert!(message_from_wire(&m2).is_none(), "a bare schema-ref must not decode without its cache");
9798 }
9799
9800 #[test]
9801 fn wire_single_struct_uncached_stays_inline_tag() {
9802 let v = point(1, 2);
9805 let bytes = message_to_wire("p", &v).unwrap();
9806 let (codec, _comp, body) = unframe(&bytes).unwrap();
9807 assert!(matches!(codec, WireCodec::Native));
9808 let mut pos = 0;
9809 skip_str(body, &mut pos).unwrap();
9810 assert_eq!(body[pos], T_STRUCT, "uncached lone struct must stay the inline T_STRUCT form");
9811 }
9812
9813 #[test]
9816 fn wire_struct_type_id_elides_names_and_beats_inline() {
9817 let v = point(1, 2);
9821 let schemas = vec![("Point".to_string(), vec!["x".to_string(), "y".to_string()])];
9822 let with_reg = with_type_registry(WireTypeRegistry::new(schemas.clone()), || {
9823 message_to_wire("p", &v).unwrap()
9824 });
9825 let inline = message_to_wire("p", &v).unwrap();
9826 assert!(
9827 with_reg.len() < inline.len(),
9828 "type-id encode ({}) must elide names vs inline ({})",
9829 with_reg.len(),
9830 inline.len()
9831 );
9832 let back = with_type_registry(WireTypeRegistry::new(schemas), || {
9834 message_from_wire(&with_reg).unwrap().1
9835 });
9836 assert_eq!(message_to_wire("p", &back).unwrap(), inline, "type-id round-trips to the exact value");
9837 }
9838
9839 #[test]
9840 fn wire_struct_type_id_falls_back_to_inline_for_unknown_type() {
9841 let v = point(1, 2);
9844 let other = vec![("Other".to_string(), vec!["a".to_string()])];
9845 let bytes = with_type_registry(WireTypeRegistry::new(other), || message_to_wire("p", &v).unwrap());
9846 assert_eq!(bytes, message_to_wire("p", &v).unwrap(), "unknown type falls back to byte-identical inline");
9847 }
9848
9849 #[test]
9850 fn wire_struct_type_id_unknown_id_fails_cleanly() {
9851 let v = point(1, 2);
9854 let schemas = vec![("Point".to_string(), vec!["x".to_string(), "y".to_string()])];
9855 let bytes = with_type_registry(WireTypeRegistry::new(schemas), || message_to_wire("p", &v).unwrap());
9856 let decoded = with_type_registry(WireTypeRegistry::new(vec![]), || message_from_wire(&bytes));
9857 assert!(decoded.is_none(), "an unresolvable type-id must fail cleanly, not mis-decode");
9858 }
9859
9860 #[test]
9863 fn wire_best_smallest_is_never_larger_than_any_single_knob() {
9864 let il = |v: Vec<i64>| RuntimeValue::List(Rc::new(RefCell::new(ListRepr::Ints(v))));
9867 let fl = |v: Vec<f64>| RuntimeValue::List(Rc::new(RefCell::new(ListRepr::Floats(v))));
9868 let workloads: Vec<(&str, RuntimeValue)> = vec![
9869 ("sequential", il((0..256).collect())),
9870 ("random", il((0..256).map(|i: i64| i.wrapping_mul(2_654_435_761)).collect())),
9871 ("repetitive", il(vec![7i64; 256])),
9872 ("clustered", il((0..256).map(|i| 1000 + (i % 8)).collect())),
9873 ("timeseries", fl((0..256).map(|i| 100.0 + i as f64 * 0.5).collect())),
9874 ("structs", RuntimeValue::List(Rc::new(RefCell::new(ListRepr::from_values(
9875 (0..40).map(|i| point(i, i * 2)).collect(),
9876 ))))),
9877 ("int map", {
9878 let mut m = MapStorage::default();
9879 for k in 0..128i64 { m.insert(RuntimeValue::Int(k), RuntimeValue::Int(k * k)); }
9880 RuntimeValue::Map(Rc::new(RefCell::new(m)))
9881 }),
9882 ("id→row map", {
9883 let mut m = MapStorage::default();
9884 for k in 0..40i64 { m.insert(RuntimeValue::Int(k), point(k, k * 2)); }
9885 RuntimeValue::Map(Rc::new(RefCell::new(m)))
9886 }),
9887 ];
9888 for (name, v) in &workloads {
9889 let best = message_to_wire_best("p", v, WireGoal::Smallest).unwrap();
9890 for num in [WireNumerics::Varint, WireNumerics::Fixed, WireNumerics::GroupVarint] {
9891 let s = with_numerics(num, || message_to_wire("p", v)).unwrap();
9892 assert!(best.len() <= s.len(), "[{name}] best {} > numerics {:?} {}", best.len(), num, s.len());
9893 }
9894 for st in [WireStructure::Off, WireStructure::Affine, WireStructure::Auto] {
9895 let s = with_structure(st, || message_to_wire("p", v)).unwrap();
9896 assert!(best.len() <= s.len(), "[{name}] best {} > structure {:?} {}", best.len(), st, s.len());
9897 }
9898 for comp in [WireCompression::None, WireCompression::Deflate, WireCompression::Lz4, WireCompression::Zstd] {
9899 let s = with_compression_codec(comp, || message_to_wire("p", v)).unwrap();
9900 assert!(best.len() <= s.len(), "[{name}] best {} > compression {:?} {}", best.len(), comp, s.len());
9901 }
9902 for f in [WireFloats::Memcpy, WireFloats::XorDelta] {
9903 let s = with_floats(f, || message_to_wire("p", v)).unwrap();
9904 assert!(best.len() <= s.len(), "[{name}] best {} > floats {:?} {}", best.len(), f, s.len());
9905 }
9906 let back = message_from_wire(&best).unwrap().1;
9909 assert_eq!(
9910 message_to_wire("p", &back).unwrap(),
9911 message_to_wire("p", v).unwrap(),
9912 "[{name}] best must round-trip to the exact value"
9913 );
9914 }
9915 }
9916
9917 #[test]
9918 fn wire_best_fastest_is_the_fixed_memcpy_form_and_round_trips() {
9919 let v = RuntimeValue::List(Rc::new(RefCell::new(ListRepr::Ints((0..100).collect()))));
9920 let fast = message_to_wire_best("p", &v, WireGoal::Fastest).unwrap();
9921 let fixed = with_numerics(WireNumerics::Fixed, || message_to_wire("p", &v)).unwrap();
9922 assert_eq!(fast, fixed, "Fastest must be the fixed memcpy-decode form");
9923 let back = message_from_wire(&fast).unwrap().1;
9924 assert_eq!(
9925 message_to_wire("p", &back).unwrap(),
9926 message_to_wire("p", &v).unwrap(),
9927 "Fastest must round-trip to the exact value"
9928 );
9929 }
9930
9931 #[test]
9932 fn wire_auto_is_the_no_brainer_default_searching_only_when_it_pays() {
9933 let scalar = RuntimeValue::Int(42);
9937 assert_eq!(
9938 message_to_wire_auto("p", &scalar).unwrap(),
9939 message_to_wire("p", &scalar).unwrap(),
9940 "a tiny message skips the search and ships the plain default"
9941 );
9942
9943 let bulk = RuntimeValue::List(Rc::new(RefCell::new(ListRepr::Ints((0..256).collect()))));
9944 let auto_bulk = message_to_wire_auto("p", &bulk).unwrap();
9945 assert_eq!(
9946 auto_bulk,
9947 message_to_wire_best("p", &bulk, WireGoal::Smallest).unwrap(),
9948 "a bulk payload gets the full Smallest search"
9949 );
9950 assert!(
9951 auto_bulk.len() < message_to_wire("p", &bulk).unwrap().len(),
9952 "and the search actually shrinks it below the default"
9953 );
9954
9955 let mut big_map = MapStorage::default();
9957 for k in 0..200i64 {
9958 big_map.insert(RuntimeValue::Int(k), RuntimeValue::Int(k * k));
9959 }
9960 for v in [scalar, bulk, RuntimeValue::Map(Rc::new(RefCell::new(big_map)))] {
9961 let a = message_to_wire_auto("p", &v).unwrap();
9962 assert!(
9963 a.len() <= message_to_wire("p", &v).unwrap().len(),
9964 "auto is never larger than the default"
9965 );
9966 let back = message_from_wire(&a).unwrap().1;
9967 assert_eq!(
9968 message_to_wire("p", &back).unwrap(),
9969 message_to_wire("p", &v).unwrap(),
9970 "auto round-trips to the exact value"
9971 );
9972 }
9973 }
9974
9975 #[test]
9976 fn receiver_limits_refuse_a_too_deeply_nested_message() {
9977 let mut v = RuntimeValue::Nothing;
9981 for _ in 0..30 {
9982 v = RuntimeValue::List(Rc::new(RefCell::new(ListRepr::from_values(vec![v]))));
9983 }
9984 let bytes = message_to_wire("p", &v).unwrap();
9985 assert!(message_from_wire(&bytes).is_some(), "default limits accept a 30-deep message");
9986 let tight = ReceiveLimits { max_depth: 10, ..Default::default() };
9987 assert!(
9988 with_receive_limits(tight, || message_from_wire(&bytes)).is_none(),
9989 "a receiver with max_depth=10 must refuse a 30-deep message"
9990 );
9991 }
9992
9993 #[test]
9994 fn receiver_survives_a_crafted_pathologically_deep_message_no_stack_overflow() {
9995 let mut bytes = vec![0x00u8, 0x00u8]; for _ in 0..8000 {
10002 bytes.push(T_LIST);
10003 bytes.push(0x01); }
10005 bytes.push(T_NOTHING);
10006 let limits = ReceiveLimits { max_depth: 16, ..Default::default() };
10010 assert!(
10011 with_receive_limits(limits, || message_from_wire(&bytes)).is_none(),
10012 "an 8000-deep crafted message must be refused, not crash the receiver"
10013 );
10014 }
10015
10016 #[test]
10017 fn receiver_refuses_a_generator_bomb_tiny_descriptor_huge_array() {
10018 let affine = |count: u64| {
10022 let mut b = vec![0x00u8, 0x00u8, T_INTS_AFFINE]; write_uvarint(zigzag(0), &mut b); write_uvarint(zigzag(1), &mut b); write_uvarint(count, &mut b);
10026 b
10027 };
10028 assert!(
10029 message_from_wire(&affine(1_000_000_000)).is_none(),
10030 "a 1e9-count affine descriptor (~12 bytes) must be refused, never allocated"
10031 );
10032 match message_from_wire(&affine(100)).unwrap().1 {
10034 RuntimeValue::List(l) => assert_eq!(l.borrow().to_values().len(), 100, "affine still expands within budget"),
10035 other => panic!("expected a List, got {other:?}"),
10036 }
10037 let tight = ReceiveLimits { max_elements: 1000, ..Default::default() };
10039 assert!(with_receive_limits(tight, || message_from_wire(&affine(100_000))).is_none(), "max_elements=1000 refuses 100k");
10040 assert!(with_receive_limits(tight, || message_from_wire(&affine(500))).is_some(), "max_elements=1000 admits 500");
10041 }
10042
10043 #[test]
10044 fn receiver_refuses_an_oversized_message_before_decoding() {
10045 let big = RuntimeValue::List(Rc::new(RefCell::new(ListRepr::Ints((0..5000).collect()))));
10048 let bytes = message_to_wire("p", &big).unwrap();
10049 assert!(message_from_wire(&bytes).is_some(), "default byte budget accepts it");
10050 let tight = ReceiveLimits { max_bytes: bytes.len() - 1, ..Default::default() };
10051 assert!(
10052 with_receive_limits(tight, || message_from_wire(&bytes)).is_none(),
10053 "a message one byte over max_bytes is refused before decode"
10054 );
10055 }
10056
10057 #[test]
10058 fn peer_profile_round_trips_and_falls_back_on_unknown() {
10059 let p = PeerProfile {
10060 limits: ReceiveLimits {
10061 max_bytes: 1 << 20,
10062 max_depth: 16,
10063 max_elements: 10_000,
10064 max_string_bytes: 4096,
10065 accept_computed: false,
10066 },
10067 registry_epoch: 0xDEAD_BEEF,
10068 features: FEAT_ZSTD | FEAT_TYPE_ID,
10069 };
10070 assert_eq!(decode_peer_profile(&encode_peer_profile(&p)), Some(p), "profile round-trips exactly");
10071 assert_eq!(
10072 decode_peer_profile(&encode_peer_profile(&PeerProfile::default())),
10073 Some(PeerProfile::default()),
10074 "the default profile round-trips"
10075 );
10076 let mut bad = encode_peer_profile(&p);
10078 bad[0] = 99;
10079 assert!(decode_peer_profile(&bad).is_none(), "an unknown profile version → None (caller uses defaults)");
10080 let full = encode_peer_profile(&p);
10082 for cut in 0..full.len() {
10083 let _ = decode_peer_profile(&full[..cut]);
10084 }
10085 assert!(decode_peer_profile(&[]).is_none());
10086 }
10087
10088 #[test]
10089 fn negotiate_restricts_the_sender_to_the_receivers_exposed_surface() {
10090 let me = PeerProfile {
10093 registry_epoch: 7,
10094 features: FEAT_ZSTD | FEAT_LZ4 | FEAT_TYPE_ID | FEAT_COMPUTED,
10095 ..Default::default()
10096 };
10097 let peer = PeerProfile {
10098 limits: ReceiveLimits { max_bytes: 4096, ..Default::default() },
10099 registry_epoch: 7,
10100 features: FEAT_LZ4 | FEAT_TYPE_ID | FEAT_COMPUTED,
10101 };
10102 let n = negotiate(&me, &peer);
10103 assert!(n.use_type_id, "matching epochs + both type-id → elide names");
10104 assert!(n.may_send_computed, "receiver accepts computed + both speak it → may ship a computation");
10105 assert_eq!(n.compression, WireCompression::Lz4, "strongest compression BOTH understand (peer lacks zstd)");
10106 assert_eq!(n.peer_max_bytes, 4096, "the receiver's byte budget surfaces to the sender");
10107
10108 let strict = PeerProfile {
10111 limits: ReceiveLimits { accept_computed: false, ..Default::default() },
10112 registry_epoch: 999,
10113 features: FEAT_TYPE_ID, };
10115 let n2 = negotiate(&me, &strict);
10116 assert!(!n2.use_type_id, "different epochs → names must travel");
10117 assert!(!n2.may_send_computed, "receiver declines code → never ship a computation");
10118 assert_eq!(n2.compression, WireCompression::None, "no shared compression → send uncompressed");
10119 }
10120
10121 #[test]
10122 fn negotiated_send_uses_all_knobs_within_the_receivers_surface() {
10123 let from = "p";
10124 let bulk = RuntimeValue::List(Rc::new(RefCell::new(ListRepr::Ints((0..256).collect()))));
10125 let default = message_to_wire(from, &bulk).unwrap();
10126 let roundtrips = |enc: &[u8]| {
10129 let back = message_from_wire(enc).unwrap().1;
10130 assert_eq!(message_to_wire(from, &back).unwrap(), default, "negotiated send must round-trip exactly");
10131 };
10132
10133 let full = Negotiated {
10136 use_type_id: false,
10137 may_send_computed: true,
10138 compression: WireCompression::Zstd,
10139 peer_max_bytes: 1 << 20,
10140 };
10141 let enc = message_to_wire_negotiated(from, &bulk, &full, WireTypeRegistry::new(Vec::new())).unwrap();
10142 assert!(enc.len() <= default.len(), "negotiated is never larger than the default");
10143 assert!(enc.len() < default.len(), "the negotiated bake-off shrinks a 256-int list");
10144 roundtrips(&enc);
10145
10146 let nocomp = Negotiated { compression: WireCompression::None, ..full };
10149 let enc_nc = message_to_wire_negotiated(from, &bulk, &nocomp, WireTypeRegistry::new(Vec::new())).unwrap();
10150 assert!(enc_nc.len() <= default.len());
10151 roundtrips(&enc_nc);
10152
10153 use crate::interpreter::StructValue;
10155 let mut fields = HashMap::new();
10156 fields.insert("organization_identifier".to_string(), RuntimeValue::Int(1));
10157 fields.insert("organization_display_name".to_string(), RuntimeValue::Text(Rc::new("ACME".to_string())));
10158 let s = RuntimeValue::Struct(Box::new(StructValue { type_name: "Organization".to_string(), fields }));
10159 let names = vec!["organization_display_name".to_string(), "organization_identifier".to_string()];
10160 let inline = message_to_wire(from, &s).unwrap();
10161 let with_id = Negotiated { use_type_id: true, ..nocomp };
10162 let elided = message_to_wire_negotiated(
10163 from,
10164 &s,
10165 &with_id,
10166 WireTypeRegistry::new(vec![("Organization".to_string(), names.clone())]),
10167 )
10168 .unwrap();
10169 assert!(elided.len() < inline.len(), "type-id elides the long field NAMES from the wire");
10170 let back = with_type_registry(
10172 WireTypeRegistry::new(vec![("Organization".to_string(), names)]),
10173 || message_from_wire(&elided),
10174 )
10175 .unwrap()
10176 .1;
10177 assert_eq!(message_to_wire(from, &back).unwrap(), inline, "the struct round-trips through the shared registry");
10178
10179 use crate::ast::stmt::{BinaryOpKind, Expr, Literal};
10181 use logicaffeine_base::{Arena, Symbol};
10182 let a: Arena<Expr> = Arena::new();
10183 let i = Symbol::from_index(0);
10184 let idx: &Expr = a.alloc(Expr::Identifier(i));
10185 let one: &Expr = a.alloc(Expr::Literal(Literal::Number(1)));
10186 let fbody: &Expr = a.alloc(Expr::BinaryOp { op: BinaryOpKind::Add, left: idx, right: one });
10187 let gen = lower_expr_to_genexpr(fbody, i).unwrap();
10188 let f = RuntimeValue::Function(Box::new(ClosureValue {
10189 body_index: usize::MAX,
10190 captured_env: std::collections::HashMap::default(),
10191 param_names: vec![i],
10192 generated: Some(Rc::new(gen)),
10193 }));
10194 let declined = Negotiated { may_send_computed: false, ..full };
10195 assert!(
10196 message_to_wire_negotiated(from, &f, &declined, WireTypeRegistry::new(Vec::new())).is_err(),
10197 "a computation the receiver declined is refused at SEND"
10198 );
10199 let accepted = Negotiated { may_send_computed: true, ..full };
10200 assert!(
10201 message_to_wire_negotiated(from, &f, &accepted, WireTypeRegistry::new(Vec::new())).is_ok(),
10202 "an accepted computation is sent"
10203 );
10204 }
10205
10206 #[test]
10207 fn wire_type_registry_epoch_is_deterministic_and_distinguishes_type_sets() {
10208 let a = WireTypeRegistry::new(vec![("Org".to_string(), vec!["id".to_string(), "name".to_string()])]);
10212 let b = WireTypeRegistry::new(vec![("Org".to_string(), vec!["name".to_string(), "id".to_string()])]);
10213 assert_eq!(a.epoch(), b.epoch(), "same types in any field order → identical epoch");
10214 assert_ne!(a.epoch(), 0, "a non-empty registry is never epoch 0");
10215 let c = WireTypeRegistry::new(vec![("User".to_string(), vec!["id".to_string()])]);
10216 assert_ne!(a.epoch(), c.epoch(), "a different type set → a different epoch");
10217 assert_eq!(WireTypeRegistry::new(vec![]).epoch(), 0, "empty registry → epoch 0 (never elide)");
10218 let with_enum = WireTypeRegistry::new(vec![("Org".to_string(), vec!["id".to_string(), "name".to_string()])])
10220 .with_enums(vec![("Color".to_string(), vec!["Red".to_string(), "Green".to_string()])]);
10221 assert_ne!(a.epoch(), with_enum.epoch(), "adding an enum type changes the epoch");
10222 }
10223
10224 #[test]
10225 fn handshake_frame_round_trips_and_is_never_confused_with_a_data_message() {
10226 let prof = PeerProfile {
10227 limits: ReceiveLimits { max_bytes: 4096, accept_computed: false, ..Default::default() },
10228 registry_epoch: 42,
10229 features: FEAT_LZ4 | FEAT_TYPE_ID,
10230 };
10231 let frame = make_handshake_frame("alice", &prof);
10232 assert_eq!(parse_handshake_frame(&frame), Some(("alice".to_string(), prof)), "handshake round-trips");
10233
10234 let data = message_to_wire("alice", &RuntimeValue::Int(7)).unwrap();
10236 assert!(parse_handshake_frame(&data).is_none(), "a data message is not a handshake");
10237 assert!(message_from_wire(&frame).is_none(), "a handshake frame is not a data message");
10239 for cut in 0..frame.len() {
10241 let _ = parse_handshake_frame(&frame[..cut]);
10242 }
10243 }
10244
10245 #[test]
10246 fn wire_struct_list_type_id_elides_names_and_beats_inline() {
10247 let v = RuntimeValue::List(Rc::new(RefCell::new(ListRepr::from_values(
10251 (0..50).map(|i| point(i, i * 2)).collect(),
10252 ))));
10253 let schemas = vec![("Point".to_string(), vec!["x".to_string(), "y".to_string()])];
10254 let with_reg = with_type_registry(WireTypeRegistry::new(schemas.clone()), || {
10255 message_to_wire("p", &v).unwrap()
10256 });
10257 let inline = message_to_wire("p", &v).unwrap();
10258 assert!(
10259 with_reg.len() < inline.len(),
10260 "struct-list type-id ({}) must elide names vs inline ({})",
10261 with_reg.len(),
10262 inline.len()
10263 );
10264 let back = with_type_registry(WireTypeRegistry::new(schemas), || {
10265 message_from_wire(&with_reg).unwrap().1
10266 });
10267 assert_eq!(
10268 message_to_wire("p", &back).unwrap(),
10269 inline,
10270 "struct-list type-id round-trips to the exact value"
10271 );
10272 }
10273
10274 #[test]
10275 fn wire_struct_list_type_id_falls_back_for_unknown_type() {
10276 let v = RuntimeValue::List(Rc::new(RefCell::new(ListRepr::from_values(
10278 (0..10).map(|i| point(i, i)).collect(),
10279 ))));
10280 let other = vec![("Other".to_string(), vec!["a".to_string()])];
10281 let bytes = with_type_registry(WireTypeRegistry::new(other), || message_to_wire("p", &v).unwrap());
10282 assert_eq!(
10283 bytes,
10284 message_to_wire("p", &v).unwrap(),
10285 "unknown type falls back to byte-identical inline T_STRUCTS"
10286 );
10287 }
10288
10289 #[test]
10290 fn wire_struct_list_type_id_unknown_id_fails_cleanly() {
10291 let v = RuntimeValue::List(Rc::new(RefCell::new(ListRepr::from_values(
10294 (0..10).map(|i| point(i, i)).collect(),
10295 ))));
10296 let schemas = vec![("Point".to_string(), vec!["x".to_string(), "y".to_string()])];
10297 let bytes = with_type_registry(WireTypeRegistry::new(schemas), || message_to_wire("p", &v).unwrap());
10298 let decoded = with_type_registry(WireTypeRegistry::new(vec![]), || message_from_wire(&bytes));
10299 assert!(decoded.is_none(), "an unresolvable struct-list type-id must fail cleanly, not mis-decode");
10300 }
10301
10302 #[test]
10303 fn wire_struct_type_id_registry_order_independent() {
10304 let v = point(7, 9);
10308 let a = vec![
10309 ("Point".to_string(), vec!["x".to_string(), "y".to_string()]),
10310 ("Other".to_string(), vec!["a".to_string()]),
10311 ];
10312 let mut b = a.clone();
10313 b.reverse();
10314 let enc_a = with_type_registry(WireTypeRegistry::new(a), || message_to_wire("p", &v).unwrap());
10315 let dec_b = with_type_registry(WireTypeRegistry::new(b), || message_from_wire(&enc_a).unwrap().1);
10316 assert_eq!(message_to_wire("p", &dec_b).unwrap(), message_to_wire("p", &v).unwrap());
10317 }
10318
10319 #[test]
10320 fn wire_enum_type_id_elides_type_and_constructor_names() {
10321 let v = enum_val("Color", "Green", vec![]);
10325 let enums = vec![("Color".to_string(), vec!["Red".to_string(), "Green".to_string(), "Blue".to_string()])];
10326 let reg = || WireTypeRegistry::new(vec![]).with_enums(enums.clone());
10327 let with_reg = with_type_registry(reg(), || message_to_wire("p", &v).unwrap());
10328 let inline = message_to_wire("p", &v).unwrap();
10329 assert!(with_reg.len() < inline.len(), "enum type-id ({}) elides names vs inline ({})", with_reg.len(), inline.len());
10330 let back = with_type_registry(reg(), || message_from_wire(&with_reg).unwrap().1);
10331 assert_eq!(message_to_wire("p", &back).unwrap(), inline, "enum type-id round-trips to the exact value");
10332 }
10333
10334 #[test]
10335 fn wire_enum_type_id_carries_args_and_falls_back_when_unknown() {
10336 let some = enum_val("Option", "Some", vec![RuntimeValue::Int(7)]);
10339 let enums = vec![("Option".to_string(), vec!["None".to_string(), "Some".to_string()])];
10340 let with_reg = with_type_registry(
10341 WireTypeRegistry::new(vec![]).with_enums(enums.clone()),
10342 || message_to_wire("p", &some).unwrap(),
10343 );
10344 let back = with_type_registry(
10345 WireTypeRegistry::new(vec![]).with_enums(enums),
10346 || message_from_wire(&with_reg).unwrap().1,
10347 );
10348 assert_eq!(message_to_wire("p", &back).unwrap(), message_to_wire("p", &some).unwrap());
10349 let other = WireTypeRegistry::new(vec![]).with_enums(vec![("X".to_string(), vec!["A".to_string()])]);
10351 let bytes = with_type_registry(other, || message_to_wire("p", &some).unwrap());
10352 assert_eq!(bytes, message_to_wire("p", &some).unwrap(), "unknown enum falls back to inline");
10353 }
10354
10355 #[test]
10358 fn wire_struct_view_round_trips() {
10359 let mut fields = HashMap::new();
10360 fields.insert("a".to_string(), RuntimeValue::Int(1));
10361 fields.insert("b".to_string(), RuntimeValue::Int(2));
10362 fields.insert("c".to_string(), RuntimeValue::Int(99));
10363 let v = RuntimeValue::Struct(Box::new(StructValue { type_name: "Rec".to_string(), fields }));
10364 let bytes = with_struct_view(true, || message_to_wire("p", &v).unwrap());
10365 let back = message_from_wire(&bytes).unwrap().1;
10366 assert_eq!(
10367 message_to_wire("p", &back).unwrap(),
10368 message_to_wire("p", &v).unwrap(),
10369 "offset-table view round-trips to the exact struct"
10370 );
10371 }
10372
10373 #[test]
10374 fn wire_struct_view_reads_one_field_without_parsing_the_rest() {
10375 let big: Vec<i64> = (0..1_000_000).map(|i| i as i64).collect();
10379 let mut fields = HashMap::new();
10380 fields.insert("big".to_string(), RuntimeValue::List(Rc::new(RefCell::new(ListRepr::Ints(big)))));
10381 fields.insert("small".to_string(), RuntimeValue::Int(4242));
10382 let v = RuntimeValue::Struct(Box::new(StructValue { type_name: "Rec".to_string(), fields }));
10383 let bytes = with_struct_view(true, || message_to_wire("p", &v).unwrap());
10387
10388 let view = view_message(&bytes).unwrap();
10389 assert_eq!(
10390 view.struct_field("small").and_then(|f| f.as_int()),
10391 Some(4242),
10392 "the offset table reads the small field directly"
10393 );
10394
10395 let reads = {
10396 let t = std::time::Instant::now();
10397 for _ in 0..1000 {
10398 let view = view_message(&bytes).unwrap();
10399 std::hint::black_box(view.struct_field("small").and_then(|f| f.as_int()));
10400 }
10401 t.elapsed().as_nanos()
10402 };
10403 let full = {
10404 let t = std::time::Instant::now();
10405 std::hint::black_box(message_from_wire(&bytes).unwrap());
10406 t.elapsed().as_nanos()
10407 };
10408 assert!(
10409 reads < full,
10410 "1000 O(1) view reads ({reads}ns) must beat ONE full decode ({full}ns) — capnp-class random access"
10411 );
10412 }
10413
10414 #[test]
10415 fn wire_aligned_int_column_reads_zero_copy_as_slice() {
10416 let data: Vec<i64> = (0..1000).map(|i| i * 7 - 3).collect();
10421 let value = RuntimeValue::List(Rc::new(RefCell::new(ListRepr::Ints(data.clone()))));
10422 let bytes = with_struct_view(true, || message_to_wire("p", &value).unwrap());
10423
10424 let mut backing = vec![0i64; bytes.len() / 8 + 2];
10428 unsafe {
10430 std::ptr::copy_nonoverlapping(bytes.as_ptr(), backing.as_mut_ptr().cast::<u8>(), bytes.len());
10431 }
10432 let abytes: &[u8] = unsafe { std::slice::from_raw_parts(backing.as_ptr().cast::<u8>(), bytes.len()) };
10433
10434 let view = view_message(abytes).unwrap();
10435 let slice = view.as_i64_slice().expect("an aligned column reads zero-copy as &[i64]");
10436 assert_eq!(slice, &data[..], "the zero-copy slice equals the column data");
10437
10438 let base = abytes.as_ptr() as usize;
10441 let lo = slice.as_ptr() as usize;
10442 assert!(lo >= base && lo < base + abytes.len(), "the slice borrows the message bytes (zero-copy)");
10443 assert_eq!(lo % 8, 0, "the column blob is 8-byte aligned");
10444
10445 let back = message_from_wire(abytes).unwrap().1;
10448 let re = with_struct_view(true, || message_to_wire("p", &back).unwrap());
10449 assert_eq!(re, bytes, "the aligned column also decodes + re-encodes to the exact bytes");
10450 }
10451
10452 #[test]
10453 fn wire_aligned_int_column_falls_back_to_copy_when_unaligned() {
10454 let data: Vec<i64> = (0..64).map(|i| i - 32).collect();
10457 let value = RuntimeValue::List(Rc::new(RefCell::new(ListRepr::Ints(data.clone()))));
10458 let bytes = with_struct_view(true, || message_to_wire("p", &value).unwrap());
10459
10460 let mut backing = vec![0i64; bytes.len() / 8 + 2];
10463 let raw = unsafe { std::slice::from_raw_parts_mut(backing.as_mut_ptr().cast::<u8>(), bytes.len() + 1) };
10464 raw[1..bytes.len() + 1].copy_from_slice(&bytes);
10465 let shifted: &[u8] = &raw[1..bytes.len() + 1];
10466
10467 let view = view_message(shifted).unwrap();
10468 if let Some(slice) = view.as_i64_slice() {
10471 assert_eq!(slice.as_ptr() as usize % 8, 0, "if it returned a slice it MUST be aligned");
10472 }
10473 let back = message_from_wire(shifted).unwrap().1;
10474 let re = with_struct_view(true, || message_to_wire("p", &back).unwrap());
10475 assert_eq!(re, bytes, "the unaligned column still decodes correctly via copy");
10476 }
10477
10478 #[test]
10479 fn wire_aligned_float_column_reads_zero_copy_as_slice() {
10480 let mut data: Vec<f64> = (0..1000).map(|i| i as f64 * 1.5 - 7.0).collect();
10484 data[3] = f64::NAN;
10485 data[5] = f64::INFINITY;
10486 data[7] = f64::NEG_INFINITY;
10487 data[9] = f64::MIN_POSITIVE / 4.0; data[11] = -0.0;
10489 let value = RuntimeValue::List(Rc::new(RefCell::new(ListRepr::Floats(data.clone()))));
10490 let bytes = with_struct_view(true, || message_to_wire("p", &value).unwrap());
10491
10492 let mut backing = vec![0i64; bytes.len() / 8 + 2];
10493 unsafe {
10495 std::ptr::copy_nonoverlapping(bytes.as_ptr(), backing.as_mut_ptr().cast::<u8>(), bytes.len());
10496 }
10497 let abytes: &[u8] = unsafe { std::slice::from_raw_parts(backing.as_ptr().cast::<u8>(), bytes.len()) };
10498
10499 let view = view_message(abytes).unwrap();
10500 let slice = view.as_f64_slice().expect("an aligned float column reads zero-copy as &[f64]");
10501 let got: Vec<u64> = slice.iter().map(|x| x.to_bits()).collect();
10503 let want: Vec<u64> = data.iter().map(|x| x.to_bits()).collect();
10504 assert_eq!(got, want, "the zero-copy float slice is bit-exact (NaN/Inf/subnormal/-0 preserved)");
10505
10506 let base = abytes.as_ptr() as usize;
10508 let lo = slice.as_ptr() as usize;
10509 assert!(lo >= base && lo < base + abytes.len(), "the float slice borrows the message bytes (zero-copy)");
10510 assert_eq!(lo % 8, 0, "the float column blob is 8-byte aligned");
10511
10512 let back = message_from_wire(abytes).unwrap().1;
10514 let re = with_struct_view(true, || message_to_wire("p", &back).unwrap());
10515 assert_eq!(re, bytes, "the aligned float column also decodes + re-encodes to the exact bytes");
10516 }
10517
10518 #[test]
10519 fn wire_structs_view_round_trips() {
10520 let mut rows = Vec::new();
10522 for i in 0..50i64 {
10523 let mut fields = HashMap::new();
10524 fields.insert("id".to_string(), RuntimeValue::Int(i));
10525 fields.insert("score".to_string(), RuntimeValue::Int(i * 3 - 7));
10526 fields.insert("active".to_string(), RuntimeValue::Bool(i % 2 == 0));
10527 rows.push(RuntimeValue::Struct(Box::new(StructValue { type_name: "Row".to_string(), fields })));
10528 }
10529 let v = RuntimeValue::List(Rc::new(RefCell::new(ListRepr::from_values(rows))));
10530 let bytes = with_struct_view(true, || message_to_wire("p", &v).unwrap());
10531 let back = message_from_wire(&bytes).unwrap().1;
10532 assert_eq!(
10533 with_struct_view(true, || message_to_wire("p", &back).unwrap()),
10534 bytes,
10535 "record-list view round-trips to the exact bytes"
10536 );
10537 }
10538
10539 #[test]
10540 fn wire_structs_view_reads_one_field_of_one_row_without_parsing_the_rest() {
10541 let big: Vec<i64> = (0..1000).collect();
10545 let mut rows = Vec::new();
10546 for i in 0..200i64 {
10547 let mut fields = HashMap::new();
10548 fields.insert("id".to_string(), RuntimeValue::Int(i * 1000 + 1));
10549 fields.insert(
10550 "blob".to_string(),
10551 RuntimeValue::List(Rc::new(RefCell::new(ListRepr::Ints(big.clone())))),
10552 );
10553 rows.push(RuntimeValue::Struct(Box::new(StructValue { type_name: "Row".to_string(), fields })));
10554 }
10555 let v = RuntimeValue::List(Rc::new(RefCell::new(ListRepr::from_values(rows))));
10556 let bytes = with_struct_view(true, || message_to_wire("p", &v).unwrap());
10557 let view = view_message(&bytes).unwrap();
10558
10559 assert_eq!(view.structs_len(), Some(200), "row count read from the view head");
10560 assert_eq!(
10561 view.structs_row_field(7, "id").and_then(|f| f.as_int()),
10562 Some(7 * 1000 + 1),
10563 "O(1) read of row 7's id"
10564 );
10565 assert_eq!(
10566 view.structs_row_field(199, "id").and_then(|f| f.as_int()),
10567 Some(199 * 1000 + 1),
10568 "O(1) read of the last row's id"
10569 );
10570 assert!(view.structs_row_field(200, "id").is_none(), "row out of range → None");
10571 assert!(view.structs_row_field(0, "nope").is_none(), "unknown field → None");
10572
10573 let idxs: Vec<usize> = (0..1000).map(|k| (k * 7) % 200).collect();
10575 let reads = {
10576 let t = std::time::Instant::now();
10577 let mut acc = 0i64;
10578 for &i in &idxs {
10579 acc = acc.wrapping_add(view.structs_row_field(i, "id").unwrap().as_int().unwrap());
10580 }
10581 std::hint::black_box(acc);
10582 t.elapsed().as_nanos()
10583 };
10584 let full = {
10585 let t = std::time::Instant::now();
10586 std::hint::black_box(message_from_wire(&bytes).unwrap());
10587 t.elapsed().as_nanos()
10588 };
10589 assert!(
10590 reads < full,
10591 "1000 O(1) row-field reads ({reads}ns) must beat ONE full decode ({full}ns) — record-list random access"
10592 );
10593 }
10594
10595 #[test]
10596 fn wire_cyclic_value_fails_cleanly_instead_of_overflowing() {
10597 let cell = Rc::new(RefCell::new(ListRepr::Boxed(vec![])));
10601 let list = RuntimeValue::List(cell.clone());
10602 *cell.borrow_mut() = ListRepr::Boxed(vec![list.clone()]); let result = message_to_wire("p", &list);
10604 *cell.borrow_mut() = ListRepr::Boxed(vec![]); assert!(result.is_err(), "a cyclic value must return Err, not overflow the stack");
10606 }
10607
10608 #[test]
10609 fn wire_deeply_nested_value_round_trips_below_the_guard() {
10610 let mut v = RuntimeValue::Int(7);
10615 for _ in 0..40 {
10616 v = RuntimeValue::List(Rc::new(RefCell::new(ListRepr::from_values(vec![v]))));
10617 }
10618 let bytes = message_to_wire("p", &v).expect("deep-but-finite nesting encodes");
10619 let back = message_from_wire(&bytes).expect("deep nesting decodes").1;
10620 assert_eq!(message_to_wire("p", &back).unwrap(), bytes, "deep nesting round-trips exactly");
10623 }
10624
10625 #[test]
10626 fn wire_schema_def_decodes_without_a_cache() {
10627 let v = struct_list(20);
10630 let mut send_cache = WireSchemaCache::default();
10631 let m1 = message_to_wire_cached("p", &v, WireCodec::Native, WireIntegrity::Raw, &mut send_cache).unwrap();
10632 let d = message_from_wire(&m1).unwrap().1;
10633 assert_eq!(message_to_wire("p", &d).unwrap(), message_to_wire("p", &v).unwrap());
10634 }
10635
10636 #[test]
10637 fn wire_schema_ref_without_cache_fails_cleanly() {
10638 let v = struct_list(20);
10641 let mut send_cache = WireSchemaCache::default();
10642 let _m1 = message_to_wire_cached("p", &v, WireCodec::Native, WireIntegrity::Raw, &mut send_cache).unwrap();
10643 let m2 = message_to_wire_cached("p", &v, WireCodec::Native, WireIntegrity::Raw, &mut send_cache).unwrap();
10644 assert!(message_from_wire(&m2).is_none(), "a schema-ref without a cache decodes to None");
10645 }
10646
10647 fn person(i: i64) -> RuntimeValue {
10648 let mut f = HashMap::new();
10649 f.insert("name".to_string(), RuntimeValue::Text(Rc::new(format!("n{i}"))));
10650 f.insert("score".to_string(), RuntimeValue::Int(i));
10651 RuntimeValue::Struct(Box::new(StructValue { type_name: "Person".to_string(), fields: f }))
10652 }
10653
10654 #[test]
10655 fn wire_schema_dictionary_distinct_schemas_get_distinct_ids() {
10656 let points = struct_list(10);
10659 let people = RuntimeValue::List(Rc::new(RefCell::new(ListRepr::Boxed((0..10).map(person).collect()))));
10660 let mut sc = WireSchemaCache::default();
10661 let mut rc = WireSchemaCache::default();
10662 let mut enc = |x: &RuntimeValue, c: &mut WireSchemaCache| {
10663 message_to_wire_cached("p", x, WireCodec::Native, WireIntegrity::Raw, c).unwrap()
10664 };
10665 let seq = [enc(&points, &mut sc), enc(&people, &mut sc), enc(&points, &mut sc), enc(&people, &mut sc)];
10666 let originals = [&points, &people, &points, &people];
10667 for (bytes, orig) in seq.iter().zip(originals) {
10668 let d = message_from_wire_cached(bytes, &mut rc).unwrap().1;
10669 assert_eq!(message_to_wire("p", &d).unwrap(), message_to_wire("p", orig).unwrap());
10670 }
10671 }
10672
10673 #[test]
10674 fn wire_schema_cache_handles_nested_struct_columns() {
10675 let inner = || RuntimeValue::List(Rc::new(RefCell::new(ListRepr::Boxed((0..3).map(|i| point(i, i)).collect()))));
10678 let outer: Vec<RuntimeValue> = (0..5)
10679 .map(|i| {
10680 let mut f = HashMap::new();
10681 f.insert("id".to_string(), RuntimeValue::Int(i));
10682 f.insert("pts".to_string(), inner());
10683 RuntimeValue::Struct(Box::new(StructValue { type_name: "Bag".to_string(), fields: f }))
10684 })
10685 .collect();
10686 let v = RuntimeValue::List(Rc::new(RefCell::new(ListRepr::Boxed(outer))));
10687 let mut sc = WireSchemaCache::default();
10688 let mut rc = WireSchemaCache::default();
10689 let mut enc = |c: &mut WireSchemaCache| message_to_wire_cached("p", &v, WireCodec::Native, WireIntegrity::Raw, c).unwrap();
10690 let m1 = enc(&mut sc);
10691 let m2 = enc(&mut sc);
10692 assert!(m2.len() < m1.len(), "nested schemas reference on the 2nd message: {} vs {}", m2.len(), m1.len());
10693 let d1 = message_from_wire_cached(&m1, &mut rc).unwrap().1;
10694 let d2 = message_from_wire_cached(&m2, &mut rc).unwrap().1;
10695 assert_eq!(message_to_wire("p", &d1).unwrap(), message_to_wire("p", &v).unwrap());
10696 assert_eq!(message_to_wire("p", &d2).unwrap(), message_to_wire("p", &v).unwrap());
10697 }
10698
10699 #[cfg(not(target_arch = "wasm32"))]
10700 #[test]
10701 fn wire_schema_cache_composes_with_compression_and_checksum() {
10702 let v = struct_list(300);
10705 let mut sc = WireSchemaCache::default();
10706 let mut rc = WireSchemaCache::default();
10707 let mut enc = |c: &mut WireSchemaCache| {
10708 with_compression_codec(WireCompression::Zstd, || {
10709 message_to_wire_cached("p", &v, WireCodec::Native, WireIntegrity::Checked, c).unwrap()
10710 })
10711 };
10712 let m1 = enc(&mut sc);
10713 let m2 = enc(&mut sc);
10714 assert!(m2.len() < m1.len(), "compressed+checked ref < def: {} vs {}", m2.len(), m1.len());
10715 assert!(message_from_wire_cached(&m1, &mut rc).is_some());
10716 let d2 = message_from_wire_cached(&m2, &mut rc).unwrap().1;
10717 assert_eq!(message_to_wire("p", &d2).unwrap(), message_to_wire("p", &v).unwrap());
10718 }
10719
10720 #[test]
10721 fn wire_schema_cache_fuzz_never_diverges_from_stateless() {
10722 fn gen_msg(rng: &mut SplitMix64) -> RuntimeValue {
10727 match rng.below(6) {
10728 0 => RuntimeValue::Int(rng.next() as i64),
10729 1 => RuntimeValue::List(Rc::new(RefCell::new(ListRepr::Ints((0..rng.below(20) as i64).collect())))),
10730 2 => struct_list(rng.below(20) as i64),
10731 3 => RuntimeValue::List(Rc::new(RefCell::new(ListRepr::Boxed(
10732 (0..rng.below(20) as i64).map(person).collect(),
10733 )))),
10734 4 => RuntimeValue::List(Rc::new(RefCell::new(ListRepr::Boxed(
10735 (0..rng.below(15)).map(|i| RuntimeValue::Text(Rc::new(format!("s{i}")))).collect(),
10736 )))),
10737 _ => RuntimeValue::List(Rc::new(RefCell::new(ListRepr::Boxed(
10738 (0..rng.below(12) as i64)
10739 .map(|i| if i % 2 == 0 { enum_val("Option", "Some", vec![RuntimeValue::Int(i)]) } else { enum_val("Option", "None", vec![]) })
10740 .collect(),
10741 )))),
10742 }
10743 }
10744 for seed in [1u64, 7, 42, 99, 1000, 0xDEAD_BEEF, 0x00AB_CDEF] {
10745 let mut rng = SplitMix64 { state: seed };
10746 let mut sc = WireSchemaCache::default();
10747 let mut rc = WireSchemaCache::default();
10748 for step in 0..120 {
10749 let v = gen_msg(&mut rng);
10750 let bytes = message_to_wire_cached("p", &v, WireCodec::Native, WireIntegrity::Raw, &mut sc).unwrap();
10751 let (_from, back) = message_from_wire_cached(&bytes, &mut rc).unwrap_or_else(|| panic!("seed {seed} step {step}: cached decode returned None"));
10752 assert_eq!(
10753 message_to_wire("p", &back).unwrap(),
10754 message_to_wire("p", &v).unwrap(),
10755 "seed {seed} step {step}: cached round-trip changed the value"
10756 );
10757 }
10758 }
10759 }
10760
10761 #[test]
10762 fn wire_schema_content_addressed_survives_multi_sender_reorder_and_loss() {
10763 fn gen(rng: &mut SplitMix64) -> RuntimeValue {
10768 match rng.below(4) {
10769 0 => struct_list(rng.below(15) as i64),
10770 1 => RuntimeValue::List(Rc::new(RefCell::new(ListRepr::Boxed((0..rng.below(15) as i64).map(person).collect())))),
10771 2 => RuntimeValue::Int(rng.next() as i64),
10772 _ => RuntimeValue::List(Rc::new(RefCell::new(ListRepr::Ints((0..rng.below(15) as i64).collect())))),
10773 }
10774 }
10775 for seed in [3u64, 17, 71, 2024, 0xFEED, 0xBADF00D] {
10776 let mut rng = SplitMix64 { state: seed };
10777 let mut sends: Vec<WireSchemaCache> = (0..3).map(|_| WireSchemaCache::content_addressed()).collect();
10779 let mut stream: Vec<(Vec<u8>, RuntimeValue)> = Vec::new();
10780 for _ in 0..80 {
10781 let s = rng.below(3) as usize;
10782 let v = gen(&mut rng);
10783 let bytes = message_to_wire_cached("p", &v, WireCodec::Native, WireIntegrity::Raw, &mut sends[s]).unwrap();
10784 stream.push((bytes, v));
10785 }
10786 for i in (1..stream.len()).rev() {
10788 let j = rng.below((i + 1) as u64) as usize;
10789 stream.swap(i, j);
10790 }
10791 let mut recv = WireSchemaCache::content_addressed();
10793 for (bytes, orig) in &stream {
10794 if rng.below(5) == 0 {
10795 continue; }
10797 if let Some((_from, back)) = message_from_wire_cached(bytes, &mut recv) {
10798 assert_eq!(
10799 message_to_wire("p", &back).unwrap(),
10800 message_to_wire("p", orig).unwrap(),
10801 "seed {seed}: a shared cache under reorder+loss decoded the WRONG value"
10802 );
10803 }
10804 }
10807 }
10808 }
10809
10810 #[test]
10811 fn wire_schema_keyframe_self_heals_after_missed_definition() {
10812 let v = struct_list(10);
10815 let mut send = WireSchemaCache::content_addressed().with_keyframe(2);
10816 let msgs: Vec<Vec<u8>> = (0..6)
10817 .map(|_| message_to_wire_cached("p", &v, WireCodec::Native, WireIntegrity::Raw, &mut send).unwrap())
10818 .collect();
10819 let mut recv = WireSchemaCache::content_addressed();
10821 assert!(message_from_wire_cached(&msgs[1], &mut recv).is_none(), "a reference before any definition → None");
10822 assert!(message_from_wire_cached(&msgs[3], &mut recv).is_some(), "the keyframe re-definition decodes and heals the cache");
10823 let d = message_from_wire_cached(&msgs[4], &mut recv).unwrap().1;
10824 assert_eq!(message_to_wire("p", &d).unwrap(), message_to_wire("p", &v).unwrap(), "references resolve after the keyframe");
10825 }
10826
10827 #[test]
10828 fn wire_schema_mode_dial_trades_size() {
10829 let v = struct_list(50);
10833 let ref_size = |mode_cache: fn() -> WireSchemaCache| {
10834 let mut c = mode_cache();
10835 let _def = message_to_wire_cached("p", &v, WireCodec::Native, WireIntegrity::Raw, &mut c).unwrap();
10836 message_to_wire_cached("p", &v, WireCodec::Native, WireIntegrity::Raw, &mut c).unwrap().len()
10837 };
10838 let seq = ref_size(WireSchemaCache::sequential);
10839 let ca = ref_size(WireSchemaCache::content_addressed);
10840 let inline = message_to_wire("p", &v).unwrap().len();
10841 assert!(seq < ca, "sequential ref ({seq}) < content-addressed ref ({ca})");
10842 assert!(ca < inline, "content-addressed ref ({ca}) < inline schema ({inline})");
10843 let mut s = WireSchemaCache::sequential();
10845 let mut r = WireSchemaCache::sequential();
10846 let m1 = message_to_wire_cached("p", &v, WireCodec::Native, WireIntegrity::Raw, &mut s).unwrap();
10847 let m2 = message_to_wire_cached("p", &v, WireCodec::Native, WireIntegrity::Raw, &mut s).unwrap();
10848 let d1 = message_from_wire_cached(&m1, &mut r).unwrap().1;
10849 let d2 = message_from_wire_cached(&m2, &mut r).unwrap().1;
10850 assert_eq!(message_to_wire("p", &d1).unwrap(), message_to_wire("p", &v).unwrap());
10851 assert_eq!(message_to_wire("p", &d2).unwrap(), message_to_wire("p", &v).unwrap());
10852 }
10853
10854 #[test]
10855 fn schema_cache_survives_a_panic_in_the_codec() {
10856 let v = struct_list(20);
10859 let mut cache = WireSchemaCache::content_addressed();
10860 let _def = message_to_wire_cached("p", &v, WireCodec::Native, WireIntegrity::Raw, &mut cache).unwrap();
10861 let r = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
10862 let _scope = CacheScope::enter(&mut cache);
10863 panic!("boom mid-codec");
10864 }));
10865 assert!(r.is_err(), "the panic propagated");
10866 let after = message_to_wire_cached("p", &v, WireCodec::Native, WireIntegrity::Raw, &mut cache).unwrap();
10868 let fresh = {
10869 let mut f = WireSchemaCache::content_addressed();
10870 message_to_wire_cached("p", &v, WireCodec::Native, WireIntegrity::Raw, &mut f).unwrap()
10871 };
10872 assert!(after.len() < fresh.len(), "cache survived the panic (ref {} < fresh def {})", after.len(), fresh.len());
10873 }
10874
10875 #[test]
10876 fn schema_cache_sequential_and_content_addressed_recv_are_disjoint() {
10877 let v = struct_list(20);
10882 let mut seq = WireSchemaCache::sequential();
10883 let s_def = message_to_wire_cached("p", &v, WireCodec::Native, WireIntegrity::Raw, &mut seq).unwrap();
10884 let s_ref = message_to_wire_cached("p", &v, WireCodec::Native, WireIntegrity::Raw, &mut seq).unwrap();
10885 let mut ca = WireSchemaCache::content_addressed();
10886 let c_def = message_to_wire_cached("p", &v, WireCodec::Native, WireIntegrity::Raw, &mut ca).unwrap();
10887 let c_ref = message_to_wire_cached("p", &v, WireCodec::Native, WireIntegrity::Raw, &mut ca).unwrap();
10888 let mut rc = WireSchemaCache::content_addressed();
10889 for (bytes, label) in [(&s_def, "seq def"), (&c_def, "ca def"), (&s_ref, "seq ref"), (&c_ref, "ca ref")] {
10890 let d = message_from_wire_cached(bytes, &mut rc).unwrap_or_else(|| panic!("{label} failed to decode")).1;
10891 assert_eq!(message_to_wire("p", &d).unwrap(), message_to_wire("p", &v).unwrap(), "{label} reconstructs the list");
10892 }
10893 }
10894
10895 #[test]
10896 fn wire_integrity_dial_toggles_the_checksum() {
10897 let v = struct_list(50);
10900 let raw = with_integrity(WireIntegrity::Raw, || message_to_wire("p", &v).unwrap());
10901 let checked = with_integrity(WireIntegrity::Checked, || message_to_wire("p", &v).unwrap());
10902 assert_eq!(raw[0] & 0x01, 0, "Raw carries no checksum");
10903 assert_eq!(checked[0] & 0x01, 0x01, "Checked sets the checksum bit");
10904 assert_eq!(checked.len(), raw.len() + 8, "the checksum is 8 bytes");
10905 assert!(message_from_wire(&raw).is_some() && message_from_wire(&checked).is_some(), "both decode");
10906 let default_bit = if default_integrity() == WireIntegrity::Checked { 0x01 } else { 0 };
10908 assert_eq!(message_to_wire("p", &v).unwrap()[0] & 0x01, default_bit, "the override does not leak");
10909 }
10910
10911 #[test]
10912 fn uvarint_byte_len_matches_write_uvarint() {
10913 for x in [0u64, 1, 127, 128, 16_383, 16_384, u32::MAX as u64, u64::MAX, 0x1234_5678_9ABC_DEF0] {
10914 let mut buf = Vec::new();
10915 write_uvarint(x, &mut buf);
10916 assert_eq!(uvarint_byte_len(x), buf.len(), "uvarint_byte_len({x:#x}) must match write_uvarint");
10917 }
10918 }
10919
10920 #[test]
10921 fn wire_json_codec_is_real_json() {
10922 let v = RuntimeValue::Text(Rc::new("hi".to_string()));
10923 let bytes = message_to_wire_with("alice", &v, WireCodec::Json, WireIntegrity::Raw).unwrap();
10924 let json: serde_json::Value = serde_json::from_slice(&bytes[1..]).expect("valid JSON body");
10926 assert_eq!(json["from"], "alice");
10927 }
10928
10929 #[test]
10930 fn wire_native_is_far_tighter_than_json() {
10931 let items: Vec<RuntimeValue> = (0..100).map(RuntimeValue::Int).collect();
10933 let v = RuntimeValue::List(Rc::new(RefCell::new(ListRepr::from_values(items))));
10934 let bin = message_to_wire_with("", &v, WireCodec::Native, WireIntegrity::Raw).unwrap();
10935 let json = message_to_wire_with("", &v, WireCodec::Json, WireIntegrity::Raw).unwrap();
10936 assert!(
10937 bin.len() * 2 < json.len(),
10938 "native ({} bytes) should be far tighter than json ({} bytes)",
10939 bin.len(),
10940 json.len()
10941 );
10942 }
10943
10944 #[test]
10945 fn wire_decoder_never_panics_on_arbitrary_bytes() {
10946 let mut rng = SplitMix64 { state: 0x1234_5678 };
10947 for _ in 0..5000 {
10948 let len = rng.below(80) as usize;
10949 let bytes: Vec<u8> = (0..len).map(|_| (rng.next() & 0xFF) as u8).collect();
10950 let _ = message_from_wire(&bytes); }
10952 for h in 0u16..=255 {
10954 let _ = message_from_wire(&[h as u8, 1, 2, 3, 4, 5, 6, 7, 8, 9]);
10955 }
10956 }
10957
10958 #[test]
10959 fn wire_decoder_never_panics_on_mutated_valid_messages() {
10960 fn archetypes() -> Vec<RuntimeValue> {
10967 vec![
10968 RuntimeValue::Int(42),
10969 RuntimeValue::List(Rc::new(RefCell::new(ListRepr::Ints((0..5).collect())))),
10970 RuntimeValue::List(Rc::new(RefCell::new(ListRepr::Floats((0..5).map(|i| i as f64 * 1.5).collect())))),
10971 RuntimeValue::List(Rc::new(RefCell::new(ListRepr::Bools((0..5).map(|i| i % 2 == 0).collect())))),
10972 RuntimeValue::List(Rc::new(RefCell::new(ListRepr::Boxed(
10973 (0..4).map(|i| RuntimeValue::Text(Rc::new(format!("s{i}")))).collect(),
10974 )))),
10975 struct_list(4),
10976 RuntimeValue::List(Rc::new(RefCell::new(ListRepr::Boxed(
10977 (0..6)
10978 .map(|i| if i % 2 == 0 { enum_val("Option", "Some", vec![RuntimeValue::Int(i)]) } else { enum_val("Option", "None", vec![]) })
10979 .collect(),
10980 )))),
10981 ]
10982 }
10983 let check = |bytes: &[u8]| {
10985 if let Some((_from, v)) = message_from_wire(bytes) {
10986 let _ = message_to_wire("p", &v);
10987 }
10988 let mut c = WireSchemaCache::content_addressed();
10989 if let Some((_from, v)) = message_from_wire_cached(bytes, &mut c) {
10990 let _ = message_to_wire("p", &v);
10991 }
10992 };
10993 let mut rng = SplitMix64 { state: 0x00AB_CDEF };
10994 for v in archetypes() {
10995 let mut sc = WireSchemaCache::content_addressed();
10997 let bases = [
10998 message_to_wire("p", &v).unwrap(),
10999 message_to_wire_cached("p", &v, WireCodec::Native, WireIntegrity::Raw, &mut sc).unwrap(),
11000 message_to_wire_cached("p", &v, WireCodec::Native, WireIntegrity::Raw, &mut sc).unwrap(),
11001 ];
11002 for base in &bases {
11003 check(base); for k in 0..base.len() {
11005 check(&base[..k]); }
11007 for i in 0..base.len() {
11008 for delta in [0x01u8, 0x40, 0x7F, 0x80, 0xFF] {
11009 let mut m = base.clone();
11010 m[i] ^= delta;
11011 check(&m); }
11013 }
11014 for _ in 0..30 {
11015 let mut m = base.clone();
11016 if !m.is_empty() {
11017 let i = rng.below(m.len() as u64) as usize;
11018 m[i] = (rng.next() & 0xFF) as u8;
11019 }
11020 check(&m); }
11022 }
11023 }
11024 }
11025
11026 #[test]
11027 fn wire_property_random_values_are_byte_stable() {
11028 for seed in [1u64, 2, 7, 42, 99, 1000, 0x00AB_CDEF, 0xDEAD_BEEF] {
11029 let mut rng = SplitMix64 { state: seed };
11030 for _ in 0..150 {
11031 let v = gen_value(&mut rng, 4);
11032 assert_wire_stable(&v);
11033 }
11034 }
11035 }
11036
11037 #[test]
11038 fn wire_packed_int_array_is_tight_and_stays_packed() {
11039 let n = 5000i64;
11040 let v = RuntimeValue::List(Rc::new(RefCell::new(ListRepr::Ints((0..n).collect()))));
11041 assert_wire_stable(&v);
11042 let bytes = message_to_wire_with("", &v, WireCodec::Native, WireIntegrity::Raw).unwrap();
11043 assert!(bytes.len() < n as usize * 3, "packed ints should be tight, was {} bytes", bytes.len());
11045 match message_from_wire(&bytes).unwrap().1 {
11046 RuntimeValue::List(l) => assert!(matches!(&*l.borrow(), ListRepr::Ints(_)), "decodes to a packed Ints buffer"),
11047 other => panic!("expected a list, got {other:?}"),
11048 }
11049 }
11050
11051 #[test]
11052 fn wire_fixed_width_int_mode_is_memcpy_and_interops() {
11053 let v = RuntimeValue::List(Rc::new(RefCell::new(ListRepr::Ints((0..1000).collect()))));
11054 let varint = message_to_wire("", &v).unwrap();
11055 let fixed = with_fixed_numerics(|| message_to_wire("", &v).unwrap());
11056 assert!(fixed.len() > varint.len(), "fixed-width should be larger than varint");
11059 assert!(fixed.len() >= 1000 * 8, "fixed is 8 bytes/int, was {}", fixed.len());
11060 let vals = |bytes: &[u8]| match message_from_wire(bytes).unwrap().1 {
11062 RuntimeValue::List(l) => l.borrow().to_values(),
11063 other => panic!("expected a list, got {other:?}"),
11064 };
11065 let expected: Vec<RuntimeValue> = (0..1000).map(RuntimeValue::Int).collect();
11066 assert_eq!(vals(&varint), expected);
11067 assert_eq!(vals(&fixed), expected);
11068 assert_eq!(message_to_wire("", &v).unwrap(), varint);
11070 }
11071
11072 #[test]
11073 fn gv_simd_decode_matches_scalar_oracle_over_fuzz() {
11074 for seed in [1u64, 2, 7, 42, 99, 1000, 0xDEAD_BEEF, 0x00AB_CDEF] {
11080 let mut rng = SplitMix64 { state: seed };
11081 for _ in 0..200 {
11082 let n = (rng.below(37)) as usize; let vals: Vec<i64> = (0..n)
11084 .map(|_| {
11085 let bits = rng.below(64) as u32; let mask = (1u128 << bits).wrapping_sub(1) as u64;
11087 let mag = (rng.next() & mask) as i64;
11088 if rng.next() & 1 == 0 { mag } else { -mag }
11089 })
11090 .collect();
11091 let mut buf = Vec::new();
11092 gv_encode(&mut buf, vals.iter().copied(), vals.len());
11093
11094 let (mut p1, mut p2) = (0usize, 0usize);
11095 let scalar = gv_decode(&buf, &mut p1).expect("scalar decode");
11096 let simd = gv_decode_dispatch(&buf, &mut p2).expect("dispatch decode");
11097
11098 assert_eq!(scalar, vals, "scalar oracle lost data (seed {seed}, n {n})");
11099 assert_eq!(simd, vals, "simd/dispatch lost data (seed {seed}, n {n})");
11100 assert_eq!(p1, p2, "decoders consumed a different byte count (seed {seed})");
11101 }
11102 }
11103 }
11104
11105 #[test]
11106 fn wire_group_varint_mode_interops_with_varint() {
11107 let v = RuntimeValue::List(Rc::new(RefCell::new(ListRepr::Ints(
11108 (0..1000).map(|i| i * i - 500_000).collect(),
11109 ))));
11110 let varint = message_to_wire("", &v).unwrap();
11111 let gv = with_numerics(WireNumerics::GroupVarint, || message_to_wire("", &v).unwrap());
11112 let vals = |bytes: &[u8]| match message_from_wire(bytes).unwrap().1 {
11115 RuntimeValue::List(l) => l.borrow().to_values(),
11116 other => panic!("expected a list, got {other:?}"),
11117 };
11118 assert_eq!(vals(&varint), vals(&gv));
11119 let expected: Vec<RuntimeValue> = (0..1000).map(|i| RuntimeValue::Int(i * i - 500_000)).collect();
11120 assert_eq!(vals(&gv), expected);
11121 assert_eq!(message_to_wire("", &v).unwrap(), varint);
11123 }
11124
11125 #[test]
11126 fn wire_packed_float_array_roundtrips_bit_exact() {
11127 let v = RuntimeValue::List(Rc::new(RefCell::new(ListRepr::Floats(vec![
11128 0.0, -0.0, 1.5, f64::NAN, f64::INFINITY, f64::NEG_INFINITY, f64::MIN, f64::MAX,
11129 ]))));
11130 assert_wire_stable(&v); match message_from_wire(&message_to_wire("", &v).unwrap()).unwrap().1 {
11132 RuntimeValue::List(l) => assert!(matches!(&*l.borrow(), ListRepr::Floats(_))),
11133 other => panic!("expected a list, got {other:?}"),
11134 }
11135 }
11136
11137 fn floats_list(vals: Vec<f64>) -> RuntimeValue {
11138 RuntimeValue::List(Rc::new(RefCell::new(ListRepr::Floats(vals))))
11139 }
11140 fn float_bits(v: &RuntimeValue) -> Vec<u64> {
11141 match v {
11142 RuntimeValue::List(l) => match &*l.borrow() {
11143 ListRepr::Floats(f) => f.iter().map(|x| x.to_bits()).collect(),
11144 other => panic!("not a float list: {other:?}"),
11145 },
11146 other => panic!("not a list: {other:?}"),
11147 }
11148 }
11149
11150 #[test]
11151 fn wire_floats_xor_is_bit_exact_including_special_values() {
11152 let vals = vec![1.0, 1.0000001, 1.0000002, f64::NAN, f64::INFINITY, f64::NEG_INFINITY, -0.0, 0.0, f64::MIN, f64::MAX, f64::MIN_POSITIVE];
11155 let v = floats_list(vals.clone());
11156 let bytes = with_floats(WireFloats::XorDelta, || message_to_wire("p", &v).unwrap());
11157 let back = message_from_wire(&bytes).unwrap().1;
11158 let orig: Vec<u64> = vals.iter().map(|x| x.to_bits()).collect();
11159 assert_eq!(float_bits(&back), orig, "XOR-delta float column is bit-exact");
11160 }
11161
11162 #[test]
11163 fn wire_floats_xor_shrinks_slow_varying() {
11164 let vals: Vec<f64> = (0..1000).map(|i| 100.0 + i as f64 * 1e-6).collect();
11167 let v = floats_list(vals);
11168 let memcpy = message_to_wire("p", &v).unwrap();
11169 let xor = with_floats(WireFloats::XorDelta, || message_to_wire("p", &v).unwrap());
11170 assert!(xor.len() < memcpy.len(), "XOR-delta shrinks a slow-varying column: {} vs {}", xor.len(), memcpy.len());
11171 assert_eq!(float_bits(&message_from_wire(&xor).unwrap().1), float_bits(&message_from_wire(&memcpy).unwrap().1));
11172 }
11173
11174 #[test]
11175 fn wire_floats_xor_never_grows() {
11176 let mut rng = SplitMix64 { state: 12345 };
11179 let vals: Vec<f64> = (0..1000).map(|_| f64::from_bits(rng.next())).collect();
11180 let v = floats_list(vals);
11181 let memcpy = message_to_wire("p", &v).unwrap();
11182 let xor = with_floats(WireFloats::XorDelta, || message_to_wire("p", &v).unwrap());
11183 assert!(xor.len() <= memcpy.len(), "XOR-delta must never grow vs memcpy: {} vs {}", xor.len(), memcpy.len());
11184 assert_eq!(float_bits(&message_from_wire(&xor).unwrap().1), float_bits(&message_from_wire(&memcpy).unwrap().1));
11185 }
11186
11187 #[test]
11188 fn wire_floats_xor_fuzz_bit_identical() {
11189 for seed in [1u64, 7, 42, 1000, 0xBEEF, 0xC0FFEE] {
11192 let mut rng = SplitMix64 { state: seed };
11193 for _ in 0..200 {
11194 let n = rng.below(30) as usize;
11195 let base = f64::from_bits(rng.next());
11196 let vals: Vec<f64> = (0..n)
11197 .map(|i| if rng.below(2) == 0 { base + i as f64 * 1e-9 } else { f64::from_bits(rng.next()) })
11198 .collect();
11199 let v = floats_list(vals.clone());
11200 let xor = with_floats(WireFloats::XorDelta, || message_to_wire("p", &v).unwrap());
11201 let orig: Vec<u64> = vals.iter().map(|x| x.to_bits()).collect();
11202 assert_eq!(float_bits(&message_from_wire(&xor).unwrap().1), orig, "seed {seed}: XOR-delta diverged");
11203 }
11204 }
11205 }
11206
11207 #[test]
11208 fn wire_packed_bool_array_is_bit_packed() {
11209 let n = 1000usize;
11210 let v = RuntimeValue::List(Rc::new(RefCell::new(ListRepr::Bools((0..n).map(|i| i % 3 == 0).collect()))));
11211 assert_wire_stable(&v);
11212 let bytes = message_to_wire_with("", &v, WireCodec::Native, WireIntegrity::Raw).unwrap();
11213 assert!(bytes.len() < n / 4, "bools must be bit-packed: {} bytes for {} bools", bytes.len(), n);
11215 match message_from_wire(&bytes).unwrap().1 {
11216 RuntimeValue::List(l) => assert!(matches!(&*l.borrow(), ListRepr::Bools(_))),
11217 other => panic!("expected a list, got {other:?}"),
11218 }
11219 }
11220
11221 #[test]
11222 fn wire_mixed_list_stays_generic() {
11223 let v = RuntimeValue::List(Rc::new(RefCell::new(ListRepr::Boxed(vec![
11224 RuntimeValue::Int(1),
11225 RuntimeValue::Text(Rc::new("x".to_string())),
11226 RuntimeValue::Bool(true),
11227 ]))));
11228 assert_wire_stable(&v);
11229 match message_from_wire(&message_to_wire("", &v).unwrap()).unwrap().1 {
11230 RuntimeValue::List(l) => assert!(matches!(&*l.borrow(), ListRepr::Boxed(_)), "a mixed list stays Boxed"),
11231 other => panic!("expected a list, got {other:?}"),
11232 }
11233 }
11234
11235 #[test]
11236 fn wire_string_array_packs_flat_and_loads_flat() {
11237 let strs = ["alpha", "", "héllo", "日本語", "emoji😀", "z"];
11238 let v = RuntimeValue::List(Rc::new(RefCell::new(ListRepr::Boxed(
11239 strs.iter().map(|s| RuntimeValue::Text(Rc::new(s.to_string()))).collect(),
11240 ))));
11241 assert_wire_stable(&v);
11243 let bytes = message_to_wire_with("", &v, WireCodec::Native, WireIntegrity::Raw).unwrap();
11244 match message_from_wire(&bytes).unwrap().1 {
11245 RuntimeValue::List(l) => {
11246 let b = l.borrow();
11247 assert!(matches!(&*b, ListRepr::Strings { .. }), "a string array loads FLAT, not per-element");
11248 assert_eq!(b.len(), strs.len());
11249 let got: Vec<String> = b
11250 .to_values()
11251 .into_iter()
11252 .map(|x| match x {
11253 RuntimeValue::Text(s) => (*s).clone(),
11254 other => panic!("expected text, got {other:?}"),
11255 })
11256 .collect();
11257 assert_eq!(got, strs);
11258 assert!(matches!(b.get(2), Some(RuntimeValue::Text(s)) if s.as_str() == "héllo"));
11260 }
11261 other => panic!("expected a list, got {other:?}"),
11262 }
11263 }
11264
11265 #[test]
11266 fn wire_flat_strings_memoize_repeated_get() {
11267 let v = RuntimeValue::List(Rc::new(RefCell::new(ListRepr::Boxed(vec![
11270 RuntimeValue::Text(Rc::new("a".to_string())),
11271 RuntimeValue::Text(Rc::new("bb".to_string())),
11272 RuntimeValue::Text(Rc::new("ccc".to_string())),
11273 ]))));
11274 let back = message_from_wire(&message_to_wire("", &v).unwrap()).unwrap().1;
11275 let RuntimeValue::List(l) = back else { panic!("expected a list") };
11276 let b = l.borrow();
11277 let (RuntimeValue::Text(first), RuntimeValue::Text(again)) = (b.get(1).unwrap(), b.get(1).unwrap())
11278 else {
11279 panic!("expected text")
11280 };
11281 assert_eq!(first.as_str(), "bb");
11282 assert!(Rc::ptr_eq(&first, &again), "a repeated get must reuse the memoized Rc, not re-allocate");
11283 }
11284
11285 #[test]
11286 fn wire_mixed_with_one_nonstring_stays_generic() {
11287 let v = RuntimeValue::List(Rc::new(RefCell::new(ListRepr::Boxed(vec![
11289 RuntimeValue::Text(Rc::new("a".to_string())),
11290 RuntimeValue::Int(1),
11291 RuntimeValue::Text(Rc::new("c".to_string())),
11292 ]))));
11293 assert_wire_stable(&v);
11294 match message_from_wire(&message_to_wire("", &v).unwrap()).unwrap().1 {
11295 RuntimeValue::List(l) => assert!(matches!(&*l.borrow(), ListRepr::Boxed(_)), "mixed stays Boxed"),
11296 other => panic!("expected a list, got {other:?}"),
11297 }
11298 }
11299
11300 #[test]
11301 fn wire_i32_packed_list_roundtrips_through_ints() {
11302 let v = RuntimeValue::List(Rc::new(RefCell::new(ListRepr::IntsI32(vec![1, -2, 3, -4, 100]))));
11305 assert_wire_stable(&v);
11306 let (_, back) = message_from_wire(&message_to_wire("", &v).unwrap()).unwrap();
11307 match back {
11308 RuntimeValue::List(l) => match &*l.borrow() {
11309 ListRepr::Ints(got) => assert_eq!(got, &vec![1i64, -2, 3, -4, 100]),
11310 other => panic!("expected Ints, got {other:?}"),
11311 },
11312 other => panic!("expected a list, got {other:?}"),
11313 }
11314 }
11315
11316 #[cfg(not(target_arch = "wasm32"))]
11322 #[test]
11323 fn wire_codec_report() {
11324 use std::time::Instant;
11325
11326 fn enc(v: &RuntimeValue, comp: WireCompression, num: WireNumerics) -> Vec<u8> {
11327 with_numerics(num, || with_compression_codec(comp, || message_to_wire("p", v).unwrap()))
11328 }
11329
11330 let ints = RuntimeValue::List(Rc::new(RefCell::new(ListRepr::Ints((0..1000).collect()))));
11331 let floats =
11332 RuntimeValue::List(Rc::new(RefCell::new(ListRepr::Floats((0..1000).map(|i| i as f64 * 1.5).collect()))));
11333 let bools = RuntimeValue::List(Rc::new(RefCell::new(ListRepr::Bools((0..1000).map(|i| i % 3 == 0).collect()))));
11334 let strings = redundant_list(200);
11335 let records = struct_list(1000);
11336 let payloads: [(&str, &RuntimeValue); 5] = [
11337 ("1000 ints", &ints),
11338 ("1000 floats", &floats),
11339 ("1000 bools", &bools),
11340 ("200 redundant strings", &strings),
11341 ("1000 structs (Point)", &records),
11342 ];
11343
11344 println!("\n=== WIRE CODEC REPORT ===");
11345 for (name, v) in payloads {
11346 let raw = enc(v, WireCompression::None, WireNumerics::Varint);
11347 let json = message_to_wire_with("p", v, WireCodec::Json, WireIntegrity::Raw).unwrap();
11348 println!(
11349 "\n{name}: native {} B | json {} B ({:.1}× tighter than json)",
11350 raw.len(),
11351 json.len(),
11352 json.len() as f64 / raw.len() as f64
11353 );
11354 for comp in [WireCompression::None, WireCompression::Deflate, WireCompression::Lz4, WireCompression::Zstd] {
11355 let b = enc(v, comp, WireNumerics::Varint);
11356 assert!(message_from_wire(&b).is_some(), "{name}/{comp:?} must round-trip");
11357 let cn = format!("{comp:?}");
11358 println!(" {cn:<8} {:>7} B ({:.2}× of native raw)", b.len(), b.len() as f64 / raw.len() as f64);
11359 }
11360 assert!(raw.len() < json.len(), "{name}: native must beat json");
11361 }
11362
11363 let red = redundant_list(1000);
11365 let raw = enc(&red, WireCompression::None, WireNumerics::Varint);
11366 let deflate = enc(&red, WireCompression::Deflate, WireNumerics::Varint);
11367 let lz4 = enc(&red, WireCompression::Lz4, WireNumerics::Varint);
11368 let zstd = enc(&red, WireCompression::Zstd, WireNumerics::Varint);
11369 assert!(lz4.len() < raw.len(), "lz4 shrinks redundant data ({} vs {})", lz4.len(), raw.len());
11370 assert!(deflate.len() < raw.len(), "deflate shrinks redundant data");
11371 assert!(zstd.len() <= deflate.len(), "zstd ratio ≤ deflate ({} vs {})", zstd.len(), deflate.len());
11372
11373 assert!(records_is_compact(&records), "columnar struct list must be compact");
11375
11376 for (name, v) in [("1000 ints", &ints), ("1000 structs", &records)] {
11378 let it = 2000u32;
11379 let t = Instant::now();
11380 let mut total = 0usize;
11381 for _ in 0..it {
11382 let b = message_to_wire("p", v).unwrap();
11383 total += message_from_wire(&b).map(|_| b.len()).unwrap();
11384 }
11385 let el = t.elapsed();
11386 println!(
11387 " throughput {name:<13}: {:>9.0} msg/s {:>7.1} MB/s",
11388 it as f64 / el.as_secs_f64(),
11389 total as f64 / el.as_secs_f64() / 1e6
11390 );
11391 }
11392 }
11393
11394 #[cfg(not(target_arch = "wasm32"))]
11395 fn records_is_compact(records: &RuntimeValue) -> bool {
11396 let b = message_to_wire("p", records).unwrap();
11397 b.len() < 6000
11398 }
11399
11400 #[test]
11401 #[ignore = "throughput benchmark — run with: cargo test -p logicaffeine-compile marshal::tests::bench_wire_throughput --release -- --ignored --nocapture"]
11402 fn bench_wire_throughput() {
11403 use bincode::Options;
11404 use std::time::Instant;
11405
11406 fn bench<F: FnMut() -> usize>(label: &str, iters: u32, mut f: F) {
11407 for _ in 0..(iters / 10).max(1) {
11408 f();
11409 } let t = Instant::now();
11411 let mut bytes = 0usize;
11412 for _ in 0..iters {
11413 bytes += f();
11414 }
11415 let el = t.elapsed();
11416 println!(
11417 " {label:<26} {:>11.0} msg/s {:>9.1} MB/s ({:>8.0?}/op)",
11418 iters as f64 / el.as_secs_f64(),
11419 bytes as f64 / el.as_secs_f64() / 1e6,
11420 el / iters
11421 );
11422 }
11423
11424 let bincode_enc = |v: &RuntimeValue| {
11426 let p = materialize(v).unwrap();
11427 let msg = rt_to_wire(&p).unwrap();
11428 wire_options().serialize(&WireMessage { from: "p".to_string(), msg }).unwrap()
11429 };
11430
11431 let mk_record = |i: i64| {
11433 let mut f = HashMap::new();
11434 f.insert("id".to_string(), RuntimeValue::Int(i));
11435 f.insert("name".to_string(), RuntimeValue::Text(Rc::new(format!("item-{i}"))));
11436 f.insert("active".to_string(), RuntimeValue::Bool(i % 2 == 0));
11437 RuntimeValue::Struct(Box::new(StructValue { type_name: "Record".to_string(), fields: f }))
11438 };
11439 let ints = RuntimeValue::List(Rc::new(RefCell::new(ListRepr::Ints((0..1000).collect()))));
11440 let floats =
11441 RuntimeValue::List(Rc::new(RefCell::new(ListRepr::Floats((0..1000).map(|i| i as f64 * 1.5).collect()))));
11442 let bools = RuntimeValue::List(Rc::new(RefCell::new(ListRepr::Bools((0..1000).map(|i| i % 3 == 0).collect()))));
11443 let strings = RuntimeValue::List(Rc::new(RefCell::new(ListRepr::Boxed(
11444 (0..200).map(|i| RuntimeValue::Text(Rc::new(format!("string-value-{i}")))).collect(),
11445 ))));
11446 let records =
11447 RuntimeValue::List(Rc::new(RefCell::new(ListRepr::Boxed((0..200).map(mk_record).collect()))));
11448
11449 let payloads: [(&str, &RuntimeValue); 5] = [
11450 ("1000 ints", &ints),
11451 ("1000 floats", &floats),
11452 ("1000 bools", &bools),
11453 ("200 strings", &strings),
11454 ("200 records", &records),
11455 ];
11456
11457 for (name, v) in payloads {
11458 let nat = message_to_wire_with("p", v, WireCodec::Native, WireIntegrity::Raw).unwrap();
11459 let json = message_to_wire_with("p", v, WireCodec::Json, WireIntegrity::Raw).unwrap();
11460 let binc = bincode_enc(v);
11461 println!(
11462 "\n=== {name}: native {} B | bincode {} B | json {} B ({:.1}× tighter than json) ===",
11463 nat.len(),
11464 binc.len(),
11465 json.len(),
11466 json.len() as f64 / nat.len() as f64
11467 );
11468 let it = 100_000;
11469 bench("native encode (raw)", it, || {
11470 message_to_wire_with("p", v, WireCodec::Native, WireIntegrity::Raw).unwrap().len()
11471 });
11472 bench("native encode (checked)", it, || {
11473 message_to_wire_with("p", v, WireCodec::Native, WireIntegrity::Checked).unwrap().len()
11474 });
11475 bench("bincode encode", it, || bincode_enc(v).len());
11476 bench("json encode", it, || {
11477 message_to_wire_with("p", v, WireCodec::Json, WireIntegrity::Raw).unwrap().len()
11478 });
11479 let nat_fixed = with_fixed_numerics(|| {
11481 message_to_wire_with("p", v, WireCodec::Native, WireIntegrity::Raw).unwrap()
11482 });
11483 if nat_fixed != nat {
11484 println!(" (fixed-width numerics: {} B vs varint {} B)", nat_fixed.len(), nat.len());
11485 bench("native encode (fixed)", it, || {
11486 with_fixed_numerics(|| message_to_wire_with("p", v, WireCodec::Native, WireIntegrity::Raw).unwrap().len())
11487 });
11488 bench("native decode (fixed)", it, || {
11489 message_from_wire(&nat_fixed).unwrap();
11490 nat_fixed.len()
11491 });
11492 }
11493 let nat_gv = with_numerics(WireNumerics::GroupVarint, || {
11496 message_to_wire_with("p", v, WireCodec::Native, WireIntegrity::Raw).unwrap()
11497 });
11498 if nat_gv != nat {
11499 println!(" (group-varint numerics: {} B vs varint {} B)", nat_gv.len(), nat.len());
11500 bench("native encode (gv)", it, || {
11501 with_numerics(WireNumerics::GroupVarint, || message_to_wire_with("p", v, WireCodec::Native, WireIntegrity::Raw).unwrap().len())
11502 });
11503 bench("native decode (gv/simd)", it, || {
11504 message_from_wire(&nat_gv).unwrap();
11505 nat_gv.len()
11506 });
11507 }
11508 bench("native decode (raw)", it, || {
11509 message_from_wire(&nat).unwrap();
11510 nat.len()
11511 });
11512 bench("bincode decode", it, || {
11513 let _: WireMessage = wire_options().deserialize(&binc).unwrap();
11514 binc.len()
11515 });
11516 bench("json decode", it, || {
11517 message_from_wire(&json).unwrap();
11518 json.len()
11519 });
11520 }
11521 }
11522
11523 struct SplitMix64 {
11526 state: u64,
11527 }
11528 impl SplitMix64 {
11529 fn next(&mut self) -> u64 {
11530 self.state = self.state.wrapping_add(0x9E37_79B9_7F4A_7C15);
11531 let mut z = self.state;
11532 z = (z ^ (z >> 30)).wrapping_mul(0xBF58_476D_1CE4_E5B9);
11533 z = (z ^ (z >> 27)).wrapping_mul(0x94D0_49BB_1331_11EB);
11534 z ^ (z >> 31)
11535 }
11536 fn below(&mut self, n: u64) -> u64 {
11537 self.next() % n
11538 }
11539 }
11540
11541 fn gen_char(rng: &mut SplitMix64) -> char {
11542 loop {
11543 if let Some(c) = char::from_u32((rng.next() % 0x11_0000) as u32) {
11544 return c;
11545 }
11546 }
11547 }
11548
11549 fn gen_string(rng: &mut SplitMix64) -> String {
11550 (0..rng.below(6)).map(|_| gen_char(rng)).collect()
11551 }
11552
11553 fn gen_value(rng: &mut SplitMix64, depth: u32) -> RuntimeValue {
11554 let kinds = if depth == 0 { 12 } else { 18 };
11556 match rng.below(kinds) {
11557 0 => RuntimeValue::Int(rng.next() as i64),
11558 1 => RuntimeValue::Float(f64::from_bits(rng.next())),
11559 2 => RuntimeValue::Bool(rng.next() & 1 == 0),
11560 3 => RuntimeValue::Char(gen_char(rng)),
11561 4 => RuntimeValue::Text(Rc::new(gen_string(rng))),
11562 5 => RuntimeValue::Nothing,
11563 6 => RuntimeValue::Duration(rng.next() as i64),
11564 7 => RuntimeValue::Date(rng.next() as i32),
11565 8 => RuntimeValue::Moment(rng.next() as i64),
11566 9 => RuntimeValue::Span { months: rng.next() as i32, days: rng.next() as i32 },
11567 10 => RuntimeValue::Time(rng.next() as i64),
11568 11 => RuntimeValue::Peer(Rc::new(gen_string(rng))),
11569 12 => RuntimeValue::List(Rc::new(RefCell::new(ListRepr::from_values(
11570 (0..rng.below(4)).map(|_| gen_value(rng, depth - 1)).collect(),
11571 )))),
11572 13 => RuntimeValue::Tuple(Rc::new((0..rng.below(4)).map(|_| gen_value(rng, depth - 1)).collect())),
11573 14 => RuntimeValue::Set(Rc::new(RefCell::new(
11574 (0..rng.below(4)).map(|_| gen_value(rng, depth - 1)).collect(),
11575 ))),
11576 15 => {
11577 let mut m = MapStorage::default();
11578 for _ in 0..rng.below(4) {
11579 m.insert(gen_value(rng, 0), gen_value(rng, depth - 1));
11581 }
11582 RuntimeValue::Map(Rc::new(RefCell::new(m)))
11583 }
11584 16 => {
11585 let mut fields = HashMap::new();
11586 for i in 0..rng.below(4) {
11587 fields.insert(format!("f{i}"), gen_value(rng, depth - 1));
11588 }
11589 RuntimeValue::Struct(Box::new(StructValue { type_name: format!("T{}", rng.below(5)), fields }))
11590 }
11591 _ => RuntimeValue::Inductive(Box::new(InductiveValue {
11592 inductive_type: format!("I{}", rng.below(5)),
11593 constructor: format!("C{}", rng.below(5)),
11594 args: (0..rng.below(4)).map(|_| gen_value(rng, depth - 1)).collect(),
11595 })),
11596 }
11597 }
11598}