1use std::cell::RefCell;
12use std::rc::Rc;
13
14use logicaffeine_runtime::RtPayload;
15
16use logicaffeine_base::describe::{
21 self, consider, deserialize_gen, detect_affine, emit_best_int_column, serialize_gen,
22 MAX_GEN_DEPTH, MAX_GEN_NODES,
23};
24pub use logicaffeine_base::describe::{gen_eval, GenCmp, GenExpr};
25
26use crate::interpreter::{
27 ClosureValue, InductiveValue, ListRepr, MapStorage, RuntimeValue, StructValue,
28};
29use logicaffeine_data::wire::{canonical_f64, canonical_f64_bits, put_f64, put_f64s};
30
31#[derive(Debug, Clone, PartialEq, Eq)]
33pub enum MarshalError {
34 NotSendable(&'static str),
37}
38
39pub fn materialize(value: &RuntimeValue) -> Result<RtPayload, MarshalError> {
41 Ok(match value {
42 RuntimeValue::Int(n) => RtPayload::Int(*n),
43 RuntimeValue::BigInt(b) => {
44 let (negative, magnitude) = b.to_le_bytes();
45 RtPayload::BigInt {
46 negative,
47 magnitude,
48 }
49 }
50 RuntimeValue::Rational(r) => {
51 let (num_negative, num_magnitude) = r.numerator().to_le_bytes();
52 let (_den_sign, den_magnitude) = r.denominator().to_le_bytes();
53 RtPayload::Rational {
54 num_negative,
55 num_magnitude,
56 den_magnitude,
57 }
58 }
59 RuntimeValue::Decimal(d) => {
60 let (negative, magnitude, scale) = d.to_le_bytes();
61 RtPayload::Decimal {
62 negative,
63 magnitude,
64 scale,
65 }
66 }
67 RuntimeValue::Money(m) => {
68 let (negative, magnitude, scale) = m.amount.to_le_bytes();
69 RtPayload::Money {
70 negative,
71 magnitude,
72 scale,
73 currency: m.currency.code.to_string(),
74 }
75 }
76 RuntimeValue::Uuid(u) => RtPayload::Uuid(u.to_bytes()),
77 RuntimeValue::Complex(c) => {
78 let (re_negative, re_num) = c.re().numerator().to_le_bytes();
79 let (_, re_den) = c.re().denominator().to_le_bytes();
80 let (im_negative, im_num) = c.im().numerator().to_le_bytes();
81 let (_, im_den) = c.im().denominator().to_le_bytes();
82 RtPayload::Complex {
83 re_negative,
84 re_num,
85 re_den,
86 im_negative,
87 im_num,
88 im_den,
89 }
90 }
91 RuntimeValue::Modular(m) => {
92 let (_, value) = m.value().to_le_bytes();
93 let (_, modulus) = m.modulus().to_le_bytes();
94 RtPayload::Modular { value, modulus }
95 }
96 RuntimeValue::Float(f) => RtPayload::Float(*f),
97 RuntimeValue::Bool(b) => RtPayload::Bool(*b),
98 RuntimeValue::Char(c) => RtPayload::Char(*c),
99 RuntimeValue::Text(s) => RtPayload::Text((**s).clone()),
100 RuntimeValue::Nothing => RtPayload::Nothing,
101 RuntimeValue::Duration(n) => RtPayload::Duration(*n),
102 RuntimeValue::Date(n) => RtPayload::Date(*n),
103 RuntimeValue::Moment(n) => RtPayload::Moment(*n),
104 RuntimeValue::Span { months, days } => RtPayload::Span {
105 months: *months,
106 days: *days,
107 },
108 RuntimeValue::Time(n) => RtPayload::Time(*n),
109 RuntimeValue::Word(w) => RtPayload::Word {
110 width: w.width(),
111 bits: w.to_u64(),
112 },
113 RuntimeValue::Lanes(_) => return Err(MarshalError::NotSendable("Lanes8Word32")),
116 RuntimeValue::ComplexF(c) => RtPayload::ComplexF {
117 re: c.re(),
118 im: c.im(),
119 },
120 RuntimeValue::List(items) => {
121 let vals = items.borrow().to_values();
122 RtPayload::List(vals.iter().map(materialize).collect::<Result<_, _>>()?)
123 }
124 RuntimeValue::Set(items) => RtPayload::Set(
125 items
126 .borrow()
127 .iter()
128 .map(materialize)
129 .collect::<Result<_, _>>()?,
130 ),
131 RuntimeValue::Tuple(items) => {
132 RtPayload::Tuple(items.iter().map(materialize).collect::<Result<_, _>>()?)
133 }
134 RuntimeValue::Map(m) => {
135 let mut pairs = Vec::new();
136 for (k, v) in m.borrow().iter() {
137 pairs.push((materialize(k)?, materialize(v)?));
138 }
139 RtPayload::Map(pairs)
140 }
141 RuntimeValue::Struct(s) => {
142 let mut fields = Vec::new();
143 for (name, v) in s.fields.iter() {
144 fields.push((name.clone(), materialize(v)?));
145 }
146 RtPayload::Struct {
147 type_name: s.type_name.clone(),
148 fields,
149 }
150 }
151 RuntimeValue::Inductive(ind) => RtPayload::Inductive {
152 type_name: ind.inductive_type.clone(),
153 constructor: ind.constructor.clone(),
154 args: ind.args.iter().map(materialize).collect::<Result<_, _>>()?,
155 },
156 RuntimeValue::Chan(id) => RtPayload::Chan(*id),
160 RuntimeValue::TaskHandle(id) => RtPayload::TaskHandle(*id),
161 RuntimeValue::Peer(topic) => RtPayload::Peer((**topic).clone()),
163 RuntimeValue::Function(_) => return Err(MarshalError::NotSendable("Function")),
164 RuntimeValue::Algebraic(_) | RuntimeValue::ExactReal(_) | RuntimeValue::Ordinal(_) => {
165 let Some((kind, bytes)) = crate::semantics::exact::exact_bytes(value) else {
166 return Err(MarshalError::NotSendable(logicaffeine_base::exact_real::STAYS_WITH_ITS_PROGRAM));
167 };
168 RtPayload::Exact { kind, bytes }
169 }
170 RuntimeValue::Hyperreal(_) | RuntimeValue::Hypernatural(_) => {
171 let Some((kind, name, residues, bytes)) = crate::semantics::exact::scaled_bytes(value) else {
172 return Err(MarshalError::NotSendable(logicaffeine_base::exact_real::STAYS_WITH_ITS_PROGRAM));
173 };
174 RtPayload::Scaled {
175 kind,
176 name,
177 residues,
178 bytes,
179 }
180 }
181 RuntimeValue::Depends(d) => {
182 let (name, residues) = crate::semantics::exact::scale_parts(&d.scale);
183 let branches = d
184 .value
185 .raw_branches()
186 .into_iter()
187 .map(|b| b.map(|b| materialize(&b.0)).transpose())
188 .collect::<Result<Vec<_>, _>>()?;
189 RtPayload::Depends {
190 name,
191 residues,
192 modulus: d.value.modulus(),
193 branches,
194 }
195 }
196 RuntimeValue::Converging(c) => RtPayload::Converging {
197 value: Box::new(materialize(c.value())?),
198 steps: c.steps(),
199 revisions: c.revisions(),
200 certificate: c.certificate().map(str::to_string),
201 },
202 RuntimeValue::View(_) => return Err(MarshalError::NotSendable("View")),
204 RuntimeValue::Action(_) => return Err(MarshalError::NotSendable("Action")),
205 RuntimeValue::Crdt(c) => RtPayload::Crdt(c.borrow().to_full_state_bytes()),
210 RuntimeValue::Quantity(qv) => {
213 let (num_negative, num_magnitude) = qv.q.magnitude_si().numerator().to_le_bytes();
214 let (_den_sign, den_magnitude) = qv.q.magnitude_si().denominator().to_le_bytes();
215 let dim = qv.q.dimension();
216 let mut dim_num = Vec::with_capacity(logicaffeine_base::BaseDim::COUNT);
217 let mut dim_den = Vec::with_capacity(logicaffeine_base::BaseDim::COUNT);
218 for d in logicaffeine_base::BaseDim::ALL {
219 let e = dim.exponent(d);
220 dim_num.push(e.numerator());
221 dim_den.push(e.denominator());
222 }
223 RtPayload::Quantity {
224 num_negative,
225 num_magnitude,
226 den_magnitude,
227 dim_num,
228 dim_den,
229 unit_symbol: qv.unit.symbol.to_string(),
230 }
231 }
232 })
233}
234
235pub fn rebuild(payload: RtPayload) -> RuntimeValue {
237 match payload {
238 RtPayload::Nothing => RuntimeValue::Nothing,
239 RtPayload::Int(n) => RuntimeValue::Int(n),
240 RtPayload::BigInt {
241 negative,
242 magnitude,
243 } => RuntimeValue::from_bigint(logicaffeine_base::BigInt::from_le_bytes(
244 negative, &magnitude,
245 )),
246 RtPayload::Rational {
247 num_negative,
248 num_magnitude,
249 den_magnitude,
250 } => {
251 let num = logicaffeine_base::BigInt::from_le_bytes(num_negative, &num_magnitude);
252 let den = logicaffeine_base::BigInt::from_le_bytes(false, &den_magnitude);
253 match logicaffeine_base::Rational::new(num.clone(), den) {
256 Some(r) => RuntimeValue::from_rational(r),
257 None => RuntimeValue::from_bigint(num),
258 }
259 }
260 RtPayload::Decimal {
261 negative,
262 magnitude,
263 scale,
264 } => RuntimeValue::Decimal(Rc::new(logicaffeine_base::Decimal::from_le_bytes(
265 negative, &magnitude, scale,
266 ))),
267 RtPayload::Money {
268 negative,
269 magnitude,
270 scale,
271 currency,
272 } => {
273 let amount = logicaffeine_base::Decimal::from_le_bytes(negative, &magnitude, scale);
274 let currency = logicaffeine_base::money::currency::by_code(¤cy).unwrap_or(
275 logicaffeine_base::Currency {
276 code: "XXX",
277 scale: 0,
278 },
279 );
280 RuntimeValue::Money(Rc::new(logicaffeine_base::Money { amount, currency }))
281 }
282 RtPayload::Uuid(bytes) => {
283 RuntimeValue::Uuid(Rc::new(logicaffeine_base::Uuid::from_bytes(bytes)))
284 }
285 RtPayload::Complex {
286 re_negative,
287 re_num,
288 re_den,
289 im_negative,
290 im_num,
291 im_den,
292 } => {
293 let mk = |neg: bool, num: &[u8], den: &[u8]| {
294 logicaffeine_base::Rational::new(
295 logicaffeine_base::BigInt::from_le_bytes(neg, num),
296 logicaffeine_base::BigInt::from_le_bytes(false, den),
297 )
298 .unwrap_or_else(logicaffeine_base::Rational::zero)
299 };
300 let re = mk(re_negative, &re_num, &re_den);
301 let im = mk(im_negative, &im_num, &im_den);
302 RuntimeValue::Complex(Rc::new(logicaffeine_base::Complex::new(re, im)))
303 }
304 RtPayload::ComplexF { re, im } => {
305 RuntimeValue::ComplexF(Rc::new(logicaffeine_base::ComplexF::new(re, im)))
306 }
307 RtPayload::Modular { value, modulus } => {
308 let v = logicaffeine_base::BigInt::from_le_bytes(false, &value);
309 let n = logicaffeine_base::BigInt::from_le_bytes(false, &modulus);
310 match logicaffeine_base::Modular::new(v, n) {
311 Some(m) => RuntimeValue::Modular(Rc::new(m)),
312 None => RuntimeValue::Nothing, }
314 }
315 RtPayload::Quantity {
316 num_negative,
317 num_magnitude,
318 den_magnitude,
319 dim_num,
320 dim_den,
321 unit_symbol,
322 } => {
323 let num = logicaffeine_base::BigInt::from_le_bytes(num_negative, &num_magnitude);
324 let den = logicaffeine_base::BigInt::from_le_bytes(false, &den_magnitude);
325 let magnitude = logicaffeine_base::Rational::new(num, den)
326 .unwrap_or_else(logicaffeine_base::Rational::zero);
327 let mut exps = [logicaffeine_base::Exp::ZERO; logicaffeine_base::BaseDim::COUNT];
329 for (i, slot) in exps.iter_mut().enumerate() {
330 let n = dim_num.get(i).copied().unwrap_or(0);
331 let d = dim_den.get(i).copied().unwrap_or(1);
332 *slot = logicaffeine_base::Exp::new(n, if d == 0 { 1 } else { d });
333 }
334 let dim = logicaffeine_base::Dimension::from_exps(exps);
335 let unit = logicaffeine_base::quantity::units::by_name(&unit_symbol)
338 .filter(|u| u.dimension == dim)
339 .unwrap_or_else(|| {
340 logicaffeine_base::Unit::linear("", dim, logicaffeine_base::Rational::one())
341 });
342 let q = logicaffeine_base::Quantity::si(magnitude, dim);
343 RuntimeValue::Quantity(Rc::new(crate::interpreter::QuantityValue { q, unit }))
344 }
345 RtPayload::Float(f) => RuntimeValue::Float(f),
346 RtPayload::Bool(b) => RuntimeValue::Bool(b),
347 RtPayload::Char(c) => RuntimeValue::Char(c),
348 RtPayload::Text(s) => RuntimeValue::Text(Rc::new(s)),
349 RtPayload::Duration(n) => RuntimeValue::Duration(n),
350 RtPayload::Date(n) => RuntimeValue::Date(n),
351 RtPayload::Moment(n) => RuntimeValue::Moment(n),
352 RtPayload::Span { months, days } => RuntimeValue::Span { months, days },
353 RtPayload::Time(n) => RuntimeValue::Time(n),
354 RtPayload::Word { width, bits } => {
355 match logicaffeine_base::WordVal::from_u64(width, bits) {
356 Some(w) => RuntimeValue::Word(w),
357 None => RuntimeValue::Int(bits as i64),
359 }
360 }
361 RtPayload::List(items) => {
362 let vals: Vec<RuntimeValue> = items.into_iter().map(rebuild).collect();
363 RuntimeValue::List(Rc::new(RefCell::new(ListRepr::from_values(vals))))
364 }
365 RtPayload::Set(items) => RuntimeValue::Set(Rc::new(RefCell::new(
366 items.into_iter().map(rebuild).collect(),
367 ))),
368 RtPayload::Tuple(items) => {
369 RuntimeValue::Tuple(Rc::new(items.into_iter().map(rebuild).collect()))
370 }
371 RtPayload::Map(pairs) => {
372 let m: MapStorage = pairs
373 .into_iter()
374 .map(|(k, v)| (rebuild(k), rebuild(v)))
375 .collect();
376 RuntimeValue::Map(Rc::new(RefCell::new(m)))
377 }
378 RtPayload::Struct { type_name, fields } => {
379 let f = fields.into_iter().map(|(k, v)| (k, rebuild(v))).collect();
380 RuntimeValue::Struct(Box::new(StructValue {
381 type_name,
382 fields: f,
383 }))
384 }
385 RtPayload::Inductive {
386 type_name,
387 constructor,
388 args,
389 } => RuntimeValue::Inductive(std::rc::Rc::new(InductiveValue {
390 inductive_type: type_name,
391 constructor,
392 args: args.into_iter().map(rebuild).collect(),
393 })),
394 RtPayload::Chan(id) => RuntimeValue::Chan(id),
395 RtPayload::TaskHandle(id) => RuntimeValue::TaskHandle(id),
396 RtPayload::Peer(topic) => RuntimeValue::Peer(Rc::new(topic)),
397 RtPayload::Exact { kind, bytes } => crate::semantics::exact::from_exact_bytes(kind, &bytes)
400 .expect("a materialized exact value rebuilds"),
401 RtPayload::Scaled {
402 kind,
403 name,
404 residues,
405 bytes,
406 } => crate::semantics::exact::from_scaled_bytes(kind, &name, &residues, &bytes)
407 .expect("a materialized scaled value rebuilds"),
408 RtPayload::Depends {
409 name,
410 residues,
411 modulus,
412 branches,
413 } => crate::semantics::exact::depends_from_parts(
414 &name,
415 &residues,
416 modulus,
417 branches.into_iter().map(|b| b.map(rebuild)).collect(),
418 )
419 .expect("a materialized dependence rebuilds"),
420 RtPayload::Converging {
421 value,
422 steps,
423 revisions,
424 certificate,
425 } => RuntimeValue::Converging(Rc::new(match certificate {
426 Some(cert) => logicaffeine_base::limit_value::Converging::settled(rebuild(*value), &cert),
427 None => logicaffeine_base::limit_value::Converging::provisional(
428 rebuild(*value),
429 steps,
430 revisions,
431 ),
432 })),
433 RtPayload::Crdt(bytes) => RuntimeValue::Crdt(Rc::new(RefCell::new(
434 crate::semantics::crdt::CrdtValue::from_full_state_bytes(&bytes),
435 ))),
436 }
437}
438
439#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)]
460enum WireValue {
461 Nothing,
462 Int(i64),
463 BigInt {
464 negative: bool,
465 magnitude: Vec<u8>,
466 },
467 Rational {
468 num_negative: bool,
469 num_magnitude: Vec<u8>,
470 den_magnitude: Vec<u8>,
471 },
472 Decimal {
473 negative: bool,
474 magnitude: Vec<u8>,
475 scale: u32,
476 },
477 Money {
478 negative: bool,
479 magnitude: Vec<u8>,
480 scale: u32,
481 currency: std::string::String,
482 },
483 Uuid([u8; 16]),
484 Complex {
485 re_negative: bool,
486 re_num: Vec<u8>,
487 re_den: Vec<u8>,
488 im_negative: bool,
489 im_num: Vec<u8>,
490 im_den: Vec<u8>,
491 },
492 ComplexF {
493 re: f64,
494 im: f64,
495 },
496 Modular {
497 value: Vec<u8>,
498 modulus: Vec<u8>,
499 },
500 Quantity {
501 num_negative: bool,
502 num_magnitude: Vec<u8>,
503 den_magnitude: Vec<u8>,
504 dim_num: Vec<i32>,
505 dim_den: Vec<i32>,
506 unit_symbol: String,
507 },
508 Float(f64),
509 Bool(bool),
510 Char(char),
511 Text(String),
512 Duration(i64),
513 Date(i32),
514 Moment(i64),
515 Span {
516 months: i32,
517 days: i32,
518 },
519 Time(i64),
520 Word {
521 width: u32,
522 bits: u64,
523 },
524 Peer(String),
525 List(Vec<WireValue>),
526 Tuple(Vec<WireValue>),
527 Set(Vec<WireValue>),
528 Map(Vec<(WireValue, WireValue)>),
529 Struct {
530 type_name: String,
531 fields: Vec<(String, WireValue)>,
532 },
533 Inductive {
534 type_name: String,
535 constructor: String,
536 args: Vec<WireValue>,
537 },
538 Exact {
539 kind: u8,
540 bytes: Vec<u8>,
541 },
542 Scaled {
543 kind: u8,
544 name: String,
545 residues: Vec<u8>,
546 bytes: Vec<u8>,
547 },
548 Depends {
549 name: String,
550 residues: Vec<u8>,
551 modulus: u64,
552 branches: Vec<Option<WireValue>>,
553 },
554 Converging {
555 value: Box<WireValue>,
556 steps: u64,
557 revisions: u64,
558 certificate: Option<String>,
559 },
560}
561
562#[derive(serde::Serialize, serde::Deserialize)]
564struct WireMessage {
565 from: String,
566 msg: WireValue,
567}
568
569fn rt_to_wire(p: &RtPayload) -> Option<WireValue> {
572 Some(match p {
573 RtPayload::Nothing => WireValue::Nothing,
574 RtPayload::Int(n) => WireValue::Int(*n),
575 RtPayload::BigInt {
576 negative,
577 magnitude,
578 } => WireValue::BigInt {
579 negative: *negative,
580 magnitude: magnitude.clone(),
581 },
582 RtPayload::Rational {
583 num_negative,
584 num_magnitude,
585 den_magnitude,
586 } => WireValue::Rational {
587 num_negative: *num_negative,
588 num_magnitude: num_magnitude.clone(),
589 den_magnitude: den_magnitude.clone(),
590 },
591 RtPayload::Decimal {
592 negative,
593 magnitude,
594 scale,
595 } => WireValue::Decimal {
596 negative: *negative,
597 magnitude: magnitude.clone(),
598 scale: *scale,
599 },
600 RtPayload::Money {
601 negative,
602 magnitude,
603 scale,
604 currency,
605 } => WireValue::Money {
606 negative: *negative,
607 magnitude: magnitude.clone(),
608 scale: *scale,
609 currency: currency.clone(),
610 },
611 RtPayload::Uuid(bytes) => WireValue::Uuid(*bytes),
612 RtPayload::ComplexF { re, im } => WireValue::ComplexF {
613 re: canonical_f64(*re),
614 im: canonical_f64(*im),
615 },
616 RtPayload::Complex {
617 re_negative,
618 re_num,
619 re_den,
620 im_negative,
621 im_num,
622 im_den,
623 } => WireValue::Complex {
624 re_negative: *re_negative,
625 re_num: re_num.clone(),
626 re_den: re_den.clone(),
627 im_negative: *im_negative,
628 im_num: im_num.clone(),
629 im_den: im_den.clone(),
630 },
631 RtPayload::Modular { value, modulus } => WireValue::Modular {
632 value: value.clone(),
633 modulus: modulus.clone(),
634 },
635 RtPayload::Quantity {
636 num_negative,
637 num_magnitude,
638 den_magnitude,
639 dim_num,
640 dim_den,
641 unit_symbol,
642 } => WireValue::Quantity {
643 num_negative: *num_negative,
644 num_magnitude: num_magnitude.clone(),
645 den_magnitude: den_magnitude.clone(),
646 dim_num: dim_num.clone(),
647 dim_den: dim_den.clone(),
648 unit_symbol: unit_symbol.clone(),
649 },
650 RtPayload::Float(f) => WireValue::Float(canonical_f64(*f)),
651 RtPayload::Bool(b) => WireValue::Bool(*b),
652 RtPayload::Char(c) => WireValue::Char(*c),
653 RtPayload::Text(s) => WireValue::Text(s.clone()),
654 RtPayload::Duration(n) => WireValue::Duration(*n),
655 RtPayload::Date(n) => WireValue::Date(*n),
656 RtPayload::Moment(n) => WireValue::Moment(*n),
657 RtPayload::Span { months, days } => WireValue::Span {
658 months: *months,
659 days: *days,
660 },
661 RtPayload::Time(n) => WireValue::Time(*n),
662 RtPayload::Word { width, bits } => WireValue::Word {
663 width: *width,
664 bits: *bits,
665 },
666 RtPayload::Peer(topic) => WireValue::Peer(topic.clone()),
667 RtPayload::List(items) => WireValue::List(rt_seq_to_wire(items)?),
668 RtPayload::Tuple(items) => WireValue::Tuple(rt_seq_to_wire(items)?),
669 RtPayload::Set(items) => WireValue::Set(rt_seq_to_wire(items)?),
670 RtPayload::Map(pairs) => {
671 let mut wire_pairs = pairs
672 .iter()
673 .map(|(k, v)| Some((rt_to_wire(k)?, rt_to_wire(v)?)))
674 .collect::<Option<Vec<_>>>()?;
675 wire_pairs.sort_by(|a, b| canon_bytes(&a.0).cmp(&canon_bytes(&b.0)));
678 WireValue::Map(wire_pairs)
679 }
680 RtPayload::Struct { type_name, fields } => {
681 let mut wire_fields = fields
682 .iter()
683 .map(|(n, v)| Some((n.clone(), rt_to_wire(v)?)))
684 .collect::<Option<Vec<_>>>()?;
685 wire_fields.sort_by(|a, b| a.0.cmp(&b.0));
687 WireValue::Struct {
688 type_name: type_name.clone(),
689 fields: wire_fields,
690 }
691 }
692 RtPayload::Inductive {
693 type_name,
694 constructor,
695 args,
696 } => WireValue::Inductive {
697 type_name: type_name.clone(),
698 constructor: constructor.clone(),
699 args: rt_seq_to_wire(args)?,
700 },
701 RtPayload::Chan(_) | RtPayload::TaskHandle(_) => return None,
703 RtPayload::Crdt(_) => return None,
708 RtPayload::Exact { kind, bytes } => WireValue::Exact {
709 kind: *kind,
710 bytes: bytes.clone(),
711 },
712 RtPayload::Scaled {
713 kind,
714 name,
715 residues,
716 bytes,
717 } => WireValue::Scaled {
718 kind: *kind,
719 name: name.clone(),
720 residues: residues.clone(),
721 bytes: bytes.clone(),
722 },
723 RtPayload::Depends {
724 name,
725 residues,
726 modulus,
727 branches,
728 } => WireValue::Depends {
729 name: name.clone(),
730 residues: residues.clone(),
731 modulus: *modulus,
732 branches: branches
733 .iter()
734 .map(|b| match b {
735 Some(p) => rt_to_wire(p).map(Some),
736 None => Some(None),
737 })
738 .collect::<Option<Vec<_>>>()?,
739 },
740 RtPayload::Converging {
741 value,
742 steps,
743 revisions,
744 certificate,
745 } => WireValue::Converging {
746 value: Box::new(rt_to_wire(value)?),
747 steps: *steps,
748 revisions: *revisions,
749 certificate: certificate.clone(),
750 },
751 })
752}
753
754fn rt_seq_to_wire(items: &[RtPayload]) -> Option<Vec<WireValue>> {
755 items.iter().map(rt_to_wire).collect()
756}
757
758fn wire_to_rt(w: WireValue) -> RtPayload {
760 match w {
761 WireValue::Nothing => RtPayload::Nothing,
762 WireValue::Int(n) => RtPayload::Int(n),
763 WireValue::BigInt {
764 negative,
765 magnitude,
766 } => RtPayload::BigInt {
767 negative,
768 magnitude,
769 },
770 WireValue::Rational {
771 num_negative,
772 num_magnitude,
773 den_magnitude,
774 } => RtPayload::Rational {
775 num_negative,
776 num_magnitude,
777 den_magnitude,
778 },
779 WireValue::Decimal {
780 negative,
781 magnitude,
782 scale,
783 } => RtPayload::Decimal {
784 negative,
785 magnitude,
786 scale,
787 },
788 WireValue::Money {
789 negative,
790 magnitude,
791 scale,
792 currency,
793 } => RtPayload::Money {
794 negative,
795 magnitude,
796 scale,
797 currency,
798 },
799 WireValue::Uuid(bytes) => RtPayload::Uuid(bytes),
800 WireValue::ComplexF { re, im } => RtPayload::ComplexF { re, im },
801 WireValue::Complex {
802 re_negative,
803 re_num,
804 re_den,
805 im_negative,
806 im_num,
807 im_den,
808 } => RtPayload::Complex {
809 re_negative,
810 re_num,
811 re_den,
812 im_negative,
813 im_num,
814 im_den,
815 },
816 WireValue::Modular { value, modulus } => RtPayload::Modular { value, modulus },
817 WireValue::Quantity {
818 num_negative,
819 num_magnitude,
820 den_magnitude,
821 dim_num,
822 dim_den,
823 unit_symbol,
824 } => RtPayload::Quantity {
825 num_negative,
826 num_magnitude,
827 den_magnitude,
828 dim_num,
829 dim_den,
830 unit_symbol,
831 },
832 WireValue::Float(f) => RtPayload::Float(f),
833 WireValue::Bool(b) => RtPayload::Bool(b),
834 WireValue::Char(c) => RtPayload::Char(c),
835 WireValue::Text(s) => RtPayload::Text(s),
836 WireValue::Duration(n) => RtPayload::Duration(n),
837 WireValue::Date(n) => RtPayload::Date(n),
838 WireValue::Moment(n) => RtPayload::Moment(n),
839 WireValue::Span { months, days } => RtPayload::Span { months, days },
840 WireValue::Time(n) => RtPayload::Time(n),
841 WireValue::Word { width, bits } => RtPayload::Word { width, bits },
842 WireValue::Peer(topic) => RtPayload::Peer(topic),
843 WireValue::List(items) => RtPayload::List(items.into_iter().map(wire_to_rt).collect()),
844 WireValue::Tuple(items) => RtPayload::Tuple(items.into_iter().map(wire_to_rt).collect()),
845 WireValue::Set(items) => RtPayload::Set(items.into_iter().map(wire_to_rt).collect()),
846 WireValue::Map(pairs) => RtPayload::Map(
847 pairs
848 .into_iter()
849 .map(|(k, v)| (wire_to_rt(k), wire_to_rt(v)))
850 .collect(),
851 ),
852 WireValue::Struct { type_name, fields } => RtPayload::Struct {
853 type_name,
854 fields: fields
855 .into_iter()
856 .map(|(n, v)| (n, wire_to_rt(v)))
857 .collect(),
858 },
859 WireValue::Inductive {
860 type_name,
861 constructor,
862 args,
863 } => RtPayload::Inductive {
864 type_name,
865 constructor,
866 args: args.into_iter().map(wire_to_rt).collect(),
867 },
868 WireValue::Exact { kind, bytes } => RtPayload::Exact { kind, bytes },
869 WireValue::Scaled {
870 kind,
871 name,
872 residues,
873 bytes,
874 } => RtPayload::Scaled {
875 kind,
876 name,
877 residues,
878 bytes,
879 },
880 WireValue::Depends {
881 name,
882 residues,
883 modulus,
884 branches,
885 } => RtPayload::Depends {
886 name,
887 residues,
888 modulus,
889 branches: branches.into_iter().map(|b| b.map(wire_to_rt)).collect(),
890 },
891 WireValue::Converging {
892 value,
893 steps,
894 revisions,
895 certificate,
896 } => RtPayload::Converging {
897 value: Box::new(wire_to_rt(*value)),
898 steps,
899 revisions,
900 certificate,
901 },
902 }
903}
904
905fn exact_payloads_valid(p: &RtPayload) -> bool {
908 use crate::semantics::exact;
909 match p {
910 RtPayload::Exact { kind, bytes } => exact::from_exact_bytes(*kind, bytes).is_some(),
911 RtPayload::Scaled {
912 kind,
913 name,
914 residues,
915 bytes,
916 } => exact::from_scaled_bytes(*kind, name, residues, bytes).is_some(),
917 RtPayload::Depends {
918 name,
919 residues,
920 modulus,
921 branches,
922 } => {
923 branches.iter().flatten().all(exact_payloads_valid)
924 && exact::depends_from_parts(
925 name,
926 residues,
927 *modulus,
928 branches
929 .iter()
930 .map(|b| b.as_ref().map(|_| RuntimeValue::Nothing))
931 .collect(),
932 )
933 .is_some()
934 }
935 RtPayload::Converging { value, .. } => exact_payloads_valid(value),
936 RtPayload::List(items) | RtPayload::Tuple(items) | RtPayload::Set(items) => {
937 items.iter().all(exact_payloads_valid)
938 }
939 RtPayload::Map(pairs) => pairs
940 .iter()
941 .all(|(k, v)| exact_payloads_valid(k) && exact_payloads_valid(v)),
942 RtPayload::Struct { fields, .. } => fields.iter().all(|(_, v)| exact_payloads_valid(v)),
943 RtPayload::Inductive { args, .. } => args.iter().all(exact_payloads_valid),
944 _ => true,
945 }
946}
947
948#[derive(Debug, Clone, Copy, PartialEq, Eq)]
958pub enum WireCodec {
959 Native,
961 Json,
963}
964
965#[derive(Debug, Clone, Copy, PartialEq, Eq)]
972pub enum WireIntegrity {
973 Raw,
975 Checked,
978}
979
980const H_CHECKED: u8 = 0x01;
984const H_COMPRESSED: u8 = 0x02;
985const H_CODEC: u8 = 0x0C; const H_JSON: u8 = 0x10;
987const H_KNOWN: u8 = H_CHECKED | H_COMPRESSED | H_CODEC | H_JSON;
988
989pub fn message_to_wire(from: &str, value: &RuntimeValue) -> Result<Vec<u8>, String> {
996 message_to_wire_with(from, value, WireCodec::Native, current_integrity())
997}
998
999pub fn encode_value_raw(v: &RuntimeValue) -> Result<Vec<u8>, String> {
1005 with_flat_lists(true, || {
1006 with_structure(WireStructure::Off, || {
1007 with_dedup(false, || {
1008 let mut out = Vec::new();
1009 native_encode(v, &mut out)?;
1010 Ok(out)
1011 })
1012 })
1013 })
1014}
1015
1016pub fn decode_value_raw(buf: &[u8]) -> Option<RuntimeValue> {
1019 let mut pos = 0usize;
1020 let v = native_decode(buf, &mut pos)?;
1021 if pos == buf.len() {
1022 Some(v)
1023 } else {
1024 None
1025 }
1026}
1027
1028#[derive(Clone, Copy, PartialEq, Eq, Debug)]
1030pub enum WireGoal {
1031 Smallest,
1034 Fastest,
1037}
1038
1039pub fn message_to_wire_best(
1051 from: &str,
1052 value: &RuntimeValue,
1053 goal: WireGoal,
1054) -> Result<Vec<u8>, String> {
1055 match goal {
1056 WireGoal::Fastest => with_numerics(WireNumerics::Fixed, || {
1057 with_structure(WireStructure::Off, || {
1058 with_floats(WireFloats::Memcpy, || {
1059 with_compression_codec(WireCompression::None, || message_to_wire(from, value))
1060 })
1061 })
1062 }),
1063 WireGoal::Smallest => smallest_over(
1064 from,
1065 value,
1066 &[
1067 WireCompression::None,
1068 WireCompression::Deflate,
1069 WireCompression::Lz4,
1070 WireCompression::Zstd,
1071 ],
1072 ),
1073 }
1074}
1075
1076fn smallest_over(
1082 from: &str,
1083 value: &RuntimeValue,
1084 compressions: &[WireCompression],
1085) -> Result<Vec<u8>, String> {
1086 let mut best: Option<Vec<u8>> = None;
1087 let dedup_opts: &[bool] = if value_has_sharing(value) {
1092 &[false, true]
1093 } else {
1094 &[false]
1095 };
1096 for num in [
1097 WireNumerics::Varint,
1098 WireNumerics::Fixed,
1099 WireNumerics::GroupVarint,
1100 ] {
1101 for st in [
1102 WireStructure::Off,
1103 WireStructure::Affine,
1104 WireStructure::Auto,
1105 ] {
1106 for fl in [WireFloats::Memcpy, WireFloats::XorDelta] {
1107 for &comp in compressions {
1108 for &dedup in dedup_opts {
1109 let bytes = with_dedup(dedup, || {
1110 with_numerics(num, || {
1111 with_structure(st, || {
1112 with_floats(fl, || {
1113 with_compression_codec(comp, || {
1114 message_to_wire(from, value)
1115 })
1116 })
1117 })
1118 })
1119 })?;
1120 if best.as_ref().map_or(true, |b| bytes.len() < b.len()) {
1121 best = Some(bytes);
1122 }
1123 }
1124 }
1125 }
1126 }
1127 }
1128 best.ok_or_else(|| "no encoding produced".to_string())
1129}
1130
1131pub fn message_to_wire_negotiated(
1139 from: &str,
1140 value: &RuntimeValue,
1141 neg: &Negotiated,
1142 registry: WireTypeRegistry,
1143) -> Result<Vec<u8>, String> {
1144 if matches!(value, RuntimeValue::Function(_)) && !neg.may_send_computed {
1145 return Err("the receiver does not accept computed (shipped-function) sends".to_string());
1146 }
1147 let default = message_to_wire(from, value)?;
1148 if default.len() <= AUTO_SEARCH_THRESHOLD && !neg.use_type_id {
1150 return Ok(default);
1151 }
1152 let codecs: Vec<WireCompression> = if neg.compression == WireCompression::None {
1153 vec![WireCompression::None]
1154 } else {
1155 vec![WireCompression::None, neg.compression]
1156 };
1157 let search = || smallest_over(from, value, &codecs);
1158 let best = if neg.use_type_id {
1160 with_type_registry(registry, search)
1161 } else {
1162 search()
1163 }?;
1164 Ok(if best.len() < default.len() {
1165 best
1166 } else {
1167 default
1168 })
1169}
1170
1171const AUTO_SEARCH_THRESHOLD: usize = 64;
1175
1176pub fn message_to_wire_auto(from: &str, value: &RuntimeValue) -> Result<Vec<u8>, String> {
1182 let default = message_to_wire(from, value)?;
1183 if default.len() <= AUTO_SEARCH_THRESHOLD {
1184 return Ok(default);
1185 }
1186 let best = message_to_wire_best(from, value, WireGoal::Smallest)?;
1188 Ok(if best.len() < default.len() {
1189 best
1190 } else {
1191 default
1192 })
1193}
1194
1195#[derive(Clone, Copy, Debug, PartialEq, Eq)]
1201pub struct ReceiveLimits {
1202 pub max_bytes: usize,
1204 pub max_depth: usize,
1207 pub max_elements: usize,
1210 pub max_string_bytes: usize,
1212 pub accept_computed: bool,
1216}
1217
1218pub const DEFAULT_RECEIVE_LIMITS: ReceiveLimits = ReceiveLimits {
1224 max_bytes: 64 << 20,
1225 max_depth: 64,
1226 max_elements: 1 << 24,
1227 max_string_bytes: 1 << 24,
1228 accept_computed: true,
1229};
1230
1231impl Default for ReceiveLimits {
1232 fn default() -> Self {
1233 DEFAULT_RECEIVE_LIMITS
1234 }
1235}
1236
1237thread_local! {
1238 static RECEIVE_LIMITS: std::cell::Cell<ReceiveLimits> =
1239 const { std::cell::Cell::new(DEFAULT_RECEIVE_LIMITS) };
1240 static DECODE_DEPTH: std::cell::Cell<usize> = const { std::cell::Cell::new(0) };
1241}
1242
1243pub fn with_receive_limits<T>(limits: ReceiveLimits, f: impl FnOnce() -> T) -> T {
1246 let prev = RECEIVE_LIMITS.with(|c| c.replace(limits));
1247 let r = f();
1248 RECEIVE_LIMITS.with(|c| c.set(prev));
1249 r
1250}
1251
1252fn receive_limits() -> ReceiveLimits {
1255 RECEIVE_LIMITS.with(std::cell::Cell::get)
1256}
1257
1258pub const FEAT_DEFLATE: u32 = 1 << 0;
1262pub const FEAT_LZ4: u32 = 1 << 1;
1264pub const FEAT_ZSTD: u32 = 1 << 2;
1266pub const FEAT_TYPE_ID: u32 = 1 << 3;
1268pub const FEAT_COMPUTED: u32 = 1 << 4;
1270pub const FEAT_FEC: u32 = 1 << 5;
1272
1273#[derive(Clone, Copy, Debug, PartialEq, Eq)]
1280pub struct PeerProfile {
1281 pub limits: ReceiveLimits,
1283 pub registry_epoch: u64,
1286 pub features: u32,
1288}
1289
1290impl Default for PeerProfile {
1291 fn default() -> Self {
1292 Self {
1293 limits: ReceiveLimits::default(),
1294 registry_epoch: 0,
1295 features: FEAT_DEFLATE | FEAT_LZ4 | FEAT_ZSTD | FEAT_TYPE_ID | FEAT_COMPUTED | FEAT_FEC,
1296 }
1297 }
1298}
1299
1300impl PeerProfile {
1301 pub const fn conservative() -> Self {
1307 Self {
1308 limits: DEFAULT_RECEIVE_LIMITS,
1309 registry_epoch: 0,
1310 features: 0,
1311 }
1312 }
1313}
1314
1315const PEER_PROFILE_VERSION: u8 = 1;
1316
1317pub fn encode_peer_profile(p: &PeerProfile) -> Vec<u8> {
1320 let mut out = Vec::with_capacity(32);
1321 out.push(PEER_PROFILE_VERSION);
1322 write_uvarint(p.limits.max_bytes as u64, &mut out);
1323 write_uvarint(p.limits.max_depth as u64, &mut out);
1324 write_uvarint(p.limits.max_elements as u64, &mut out);
1325 write_uvarint(p.limits.max_string_bytes as u64, &mut out);
1326 out.push(p.limits.accept_computed as u8);
1327 write_uvarint(p.registry_epoch, &mut out);
1328 write_uvarint(p.features as u64, &mut out);
1329 out
1330}
1331
1332pub fn decode_peer_profile(buf: &[u8]) -> Option<PeerProfile> {
1335 let mut pos = 0;
1336 let version = *buf.get(pos)?;
1337 pos += 1;
1338 if version != PEER_PROFILE_VERSION {
1339 return None;
1340 }
1341 let max_bytes = read_uvarint(buf, &mut pos)? as usize;
1342 let max_depth = read_uvarint(buf, &mut pos)? as usize;
1343 let max_elements = read_uvarint(buf, &mut pos)? as usize;
1344 let max_string_bytes = read_uvarint(buf, &mut pos)? as usize;
1345 let accept_computed = *buf.get(pos)? != 0;
1346 pos += 1;
1347 let registry_epoch = read_uvarint(buf, &mut pos)?;
1348 let features = read_uvarint(buf, &mut pos)? as u32;
1349 Some(PeerProfile {
1350 limits: ReceiveLimits {
1351 max_bytes,
1352 max_depth,
1353 max_elements,
1354 max_string_bytes,
1355 accept_computed,
1356 },
1357 registry_epoch,
1358 features,
1359 })
1360}
1361
1362#[derive(Clone, Copy, Debug, PartialEq, Eq)]
1364pub struct Negotiated {
1365 pub use_type_id: bool,
1368 pub may_send_computed: bool,
1371 pub compression: WireCompression,
1373 pub peer_max_bytes: usize,
1375}
1376
1377pub fn negotiate(mine: &PeerProfile, theirs: &PeerProfile) -> Negotiated {
1383 let both = |bit: u32| mine.features & bit != 0 && theirs.features & bit != 0;
1384 let compression = if both(FEAT_ZSTD) {
1385 WireCompression::Zstd
1386 } else if both(FEAT_LZ4) {
1387 WireCompression::Lz4
1388 } else if both(FEAT_DEFLATE) {
1389 WireCompression::Deflate
1390 } else {
1391 WireCompression::None
1392 };
1393 Negotiated {
1394 use_type_id: both(FEAT_TYPE_ID)
1395 && mine.registry_epoch != 0
1396 && mine.registry_epoch == theirs.registry_epoch,
1397 may_send_computed: theirs.limits.accept_computed && both(FEAT_COMPUTED),
1398 compression,
1399 peer_max_bytes: theirs.limits.max_bytes,
1400 }
1401}
1402
1403const HANDSHAKE_MAGIC: &[u8; 4] = b"LCHS";
1407
1408pub fn make_handshake_frame(from: &str, profile: &PeerProfile) -> Vec<u8> {
1412 let mut out = Vec::with_capacity(8 + from.len() + 16);
1413 out.extend_from_slice(HANDSHAKE_MAGIC);
1414 write_str(from, &mut out);
1415 out.extend_from_slice(&encode_peer_profile(profile));
1416 out
1417}
1418
1419pub fn parse_handshake_frame(data: &[u8]) -> Option<(String, PeerProfile)> {
1423 let rest = data.strip_prefix(HANDSHAKE_MAGIC.as_slice())?;
1424 let mut pos = 0;
1425 let from = read_str(rest, &mut pos)?;
1426 let profile = decode_peer_profile(rest.get(pos..)?)?;
1427 Some((from, profile))
1428}
1429
1430pub fn message_to_wire_with(
1432 from: &str,
1433 value: &RuntimeValue,
1434 codec: WireCodec,
1435 integrity: WireIntegrity,
1436) -> Result<Vec<u8>, String> {
1437 let mut body = match codec {
1438 WireCodec::Native => {
1440 let mut out = Vec::with_capacity(from.len() + 32);
1443 write_str(from, &mut out);
1444 native_encode(value, &mut out)?;
1445 out
1446 }
1447 WireCodec::Json => {
1449 let payload = materialize(value).map_err(|MarshalError::NotSendable(t)| {
1450 format!("a {t} cannot be sent over the network")
1451 })?;
1452 let msg = rt_to_wire(&payload).ok_or_else(|| {
1453 "a channel or task handle cannot be sent over the network".to_string()
1454 })?;
1455 serde_json::to_vec(&WireMessage {
1456 from: from.to_string(),
1457 msg,
1458 })
1459 .map_err(|e| format!("message encode failed: {e}"))?
1460 }
1461 };
1462 let mut compression = WireCompression::None;
1465 if let Some((used, z)) = compress_body(compression_codec(), &body) {
1466 if z.len() < body.len() {
1467 body = z;
1468 compression = used;
1469 }
1470 }
1471 Ok(frame(codec, integrity, compression, body))
1472}
1473
1474pub fn message_from_wire(bytes: &[u8]) -> Option<(String, RuntimeValue)> {
1480 if bytes.len() > receive_limits().max_bytes {
1483 return None;
1484 }
1485 DECODE_MEMO.with(|c| c.borrow_mut().clear());
1487 let (codec, compression, framed) = unframe(bytes)?;
1488 let inflated;
1492 let body: &[u8] = if compression == WireCompression::None {
1493 framed
1494 } else {
1495 inflated = decompress_body(compression, framed)?;
1496 &inflated
1497 };
1498 match codec {
1499 WireCodec::Native => {
1500 let mut pos = 0;
1501 let from = read_str(body, &mut pos)?;
1502 let value = native_decode(body, &mut pos)?;
1503 (pos == body.len()).then_some((from, value)) }
1505 WireCodec::Json => {
1506 let WireMessage { from, msg } = serde_json::from_slice(body).ok()?;
1507 let payload = wire_to_rt(msg);
1508 exact_payloads_valid(&payload).then(|| (from, rebuild(payload)))
1509 }
1510 }
1511}
1512
1513fn column_tag_name(tag: u8) -> &'static str {
1517 match tag {
1518 T_INTS => "varint",
1519 T_INTS_FIXED => "fixed (memcpy)",
1520 T_INTS_GV => "group-varint",
1521 T_INTS_ALIGNED => "fixed-aligned",
1522 T_INTS_AFFINE => "affine (base,stride,n)",
1523 T_INTS_DELTA => "delta",
1524 T_INTS_DOD => "delta-of-delta",
1525 T_INTS_FOR => "FOR bit-pack",
1526 T_INTS_RLE => "run-length",
1527 T_INTS_DICT => "dictionary",
1528 T_INTS_POLY => "polynomial",
1529 T_INTS_GEOMETRIC => "geometric",
1530 T_INTS_PERIODIC => "periodic",
1531 T_INTS_SPARSE => "sparse",
1532 T_GEN => "generator",
1533 T_BYTES => "byte column",
1534 describe::T_INTS_LRECUR => "linear-recurrence",
1535 describe::T_INTS_LFSR => "LFSR",
1536 describe::T_INTS_FCSR => "FCSR",
1537 T_FLOATS => "memcpy floats",
1538 T_FLOATS_XOR => "xor-delta floats",
1539 T_FLOATS_CONST => "constant floats",
1540 T_FLOATS_AFFINE => "affine floats",
1541 T_FLOATS_SPARSE => "sparse floats",
1542 T_FLOATS_PERIODIC => "periodic floats",
1543 T_FLOATS_GEOMETRIC => "geometric floats",
1544 T_FLOATS_ALIGNED => "aligned floats",
1545 T_BOOLS => "bit-packed bools",
1546 T_BOOLS_PERIODIC => "periodic bools",
1547 T_BOOLS_RLE => "run-length bools",
1548 T_STRINGS => "flat strings",
1549 T_STRINGS_TEMPLATE => "templated strings",
1550 T_STRINGS_FRONT => "front-coded strings",
1551 T_STRINGS_AFFIX => "affix strings",
1552 T_STRINGS_DICT => "dictionary strings",
1553 T_SET_INTS => "int set (column menu)",
1554 T_SET_STRINGS => "string set (front-coded)",
1555 T_MAP_INTKEY => "int-keyed map (columnar)",
1556 _ => "value",
1557 }
1558}
1559
1560pub fn describe_columns(bytes: &[u8]) -> Vec<String> {
1568 describe_columns_inner(bytes).unwrap_or_default()
1569}
1570
1571fn describe_columns_inner(bytes: &[u8]) -> Option<Vec<String>> {
1572 let (codec, compression, body) = unframe(bytes)?;
1573 if !matches!(codec, WireCodec::Native) || compression != WireCompression::None {
1574 return None; }
1576 DECODE_MEMO.with(|c| c.borrow_mut().clear());
1577 let mut pos = 0;
1578 let _from = read_str(body, &mut pos)?;
1579 let tag = *body.get(pos)?;
1580 if tag == T_STRUCTS {
1581 let mut p = pos + 1;
1582 let (_type_name, field_names) = read_struct_schema(body, &mut p)?;
1583 let _rows = read_uvarint(body, &mut p)?;
1584 let mut out = Vec::with_capacity(field_names.len());
1585 for name in &field_names {
1586 let col_tag = *body.get(p)?;
1587 native_decode(body, &mut p)?; out.push(format!("{name}: {}", column_tag_name(col_tag)));
1589 }
1590 return Some(out);
1591 }
1592 Some(vec![column_tag_name(tag).to_string()])
1593}
1594
1595#[derive(Clone, Copy, PartialEq, Eq, Debug, Default)]
1598pub enum WireSchemaMode {
1599 #[default]
1601 Off,
1602 Sequential,
1606 ContentAddressed,
1612}
1613
1614#[derive(Debug)]
1622pub struct WireSchemaCache {
1623 mode: WireSchemaMode,
1624 send_seq: std::collections::HashMap<(String, Vec<String>), u32>,
1626 recv_seq: Vec<(String, Vec<String>)>,
1627 next: u32,
1628 send_ca: std::collections::HashSet<u64>,
1630 recv_ca: std::collections::HashMap<u64, (String, Vec<String>)>,
1631 keyframe: Option<u32>,
1633 refs_since_def: std::collections::HashMap<u64, u32>,
1634}
1635
1636impl Default for WireSchemaCache {
1637 fn default() -> Self {
1639 Self::with_mode(WireSchemaMode::ContentAddressed)
1640 }
1641}
1642
1643impl WireSchemaCache {
1644 fn with_mode(mode: WireSchemaMode) -> Self {
1645 Self {
1646 mode,
1647 send_seq: std::collections::HashMap::new(),
1648 recv_seq: Vec::new(),
1649 next: 0,
1650 send_ca: std::collections::HashSet::new(),
1651 recv_ca: std::collections::HashMap::new(),
1652 keyframe: None,
1653 refs_since_def: std::collections::HashMap::new(),
1654 }
1655 }
1656 pub fn content_addressed() -> Self {
1658 Self::with_mode(WireSchemaMode::ContentAddressed)
1659 }
1660 pub fn sequential() -> Self {
1662 Self::with_mode(WireSchemaMode::Sequential)
1663 }
1664 pub fn with_keyframe(mut self, k: u32) -> Self {
1667 self.keyframe = Some(k);
1668 self
1669 }
1670}
1671
1672fn schema_fingerprint(type_name: &str, field_names: &[String]) -> u64 {
1676 let mut bytes = Vec::with_capacity(type_name.len() + 8);
1677 bytes.extend_from_slice(type_name.as_bytes());
1678 for f in field_names {
1679 bytes.push(0);
1680 bytes.extend_from_slice(f.as_bytes());
1681 }
1682 fnv1a_64(&bytes)
1683}
1684
1685enum SchemaEmit {
1687 Inline,
1688 SeqDef(u32),
1689 SeqRef(u32),
1690 CaDef,
1691 CaRef(u64),
1692}
1693
1694thread_local! {
1695 static SCHEMA_CACHE: RefCell<Option<WireSchemaCache>> = const { RefCell::new(None) };
1698}
1699
1700struct CacheScope<'a> {
1704 cache: &'a mut WireSchemaCache,
1705}
1706impl<'a> CacheScope<'a> {
1707 fn enter(cache: &'a mut WireSchemaCache) -> Self {
1708 SCHEMA_CACHE.with(|c| *c.borrow_mut() = Some(std::mem::take(cache)));
1709 Self { cache }
1710 }
1711}
1712impl Drop for CacheScope<'_> {
1713 fn drop(&mut self) {
1714 SCHEMA_CACHE.with(|c| *self.cache = c.borrow_mut().take().unwrap_or_default());
1715 }
1716}
1717
1718pub fn message_to_wire_cached(
1721 from: &str,
1722 value: &RuntimeValue,
1723 codec: WireCodec,
1724 integrity: WireIntegrity,
1725 cache: &mut WireSchemaCache,
1726) -> Result<Vec<u8>, String> {
1727 let _scope = CacheScope::enter(cache);
1728 message_to_wire_with(from, value, codec, integrity)
1729}
1730
1731pub fn message_from_wire_cached(
1734 bytes: &[u8],
1735 cache: &mut WireSchemaCache,
1736) -> Option<(String, RuntimeValue)> {
1737 let _scope = CacheScope::enter(cache);
1738 message_from_wire(bytes)
1739}
1740
1741fn schema_send(type_name: &str, field_names: &[String]) -> SchemaEmit {
1743 SCHEMA_CACHE.with(|c| {
1744 let mut g = c.borrow_mut();
1745 let Some(cache) = g.as_mut() else {
1746 return SchemaEmit::Inline;
1747 };
1748 match cache.mode {
1749 WireSchemaMode::Off => SchemaEmit::Inline,
1750 WireSchemaMode::Sequential => {
1751 let key = (type_name.to_string(), field_names.to_vec());
1752 if let Some(&id) = cache.send_seq.get(&key) {
1753 SchemaEmit::SeqRef(id)
1754 } else {
1755 let id = cache.next;
1756 cache.next += 1;
1757 cache.send_seq.insert(key, id);
1758 SchemaEmit::SeqDef(id)
1759 }
1760 }
1761 WireSchemaMode::ContentAddressed => {
1762 let fp = schema_fingerprint(type_name, field_names);
1763 let known = cache.send_ca.contains(&fp);
1764 let count = cache.refs_since_def.entry(fp).or_insert(0);
1765 let keyframe_due = matches!(cache.keyframe, Some(k) if known && *count >= k);
1766 if known && !keyframe_due {
1767 *count += 1;
1768 SchemaEmit::CaRef(fp)
1769 } else {
1770 *count = 0;
1771 cache.send_ca.insert(fp);
1772 SchemaEmit::CaDef
1773 }
1774 }
1775 }
1776 })
1777}
1778
1779fn schema_recv_register_seq(id: u32, type_name: &str, field_names: &[String]) -> bool {
1783 SCHEMA_CACHE.with(|c| {
1784 let mut g = c.borrow_mut();
1785 let Some(cache) = g.as_mut() else { return true };
1786 let entry = (type_name.to_string(), field_names.to_vec());
1787 let idx = id as usize;
1788 if idx == cache.recv_seq.len() {
1789 cache.recv_seq.push(entry);
1790 true
1791 } else if idx < cache.recv_seq.len() {
1792 cache.recv_seq[idx] == entry
1793 } else {
1794 false
1795 }
1796 })
1797}
1798
1799fn schema_recv_lookup_seq(id: u32) -> Option<(String, Vec<String>)> {
1801 SCHEMA_CACHE.with(|c| {
1802 c.borrow()
1803 .as_ref()
1804 .and_then(|cache| cache.recv_seq.get(id as usize).cloned())
1805 })
1806}
1807
1808fn schema_recv_register_ca(type_name: &str, field_names: &[String]) -> bool {
1812 SCHEMA_CACHE.with(|c| {
1813 let mut g = c.borrow_mut();
1814 let Some(cache) = g.as_mut() else { return true };
1815 let fp = schema_fingerprint(type_name, field_names);
1816 let entry = (type_name.to_string(), field_names.to_vec());
1817 match cache.recv_ca.get(&fp) {
1818 Some(existing) => *existing == entry, None => {
1820 cache.recv_ca.insert(fp, entry);
1821 true
1822 }
1823 }
1824 })
1825}
1826
1827fn schema_recv_lookup_ca(fp: u64) -> Option<(String, Vec<String>)> {
1830 SCHEMA_CACHE.with(|c| {
1831 c.borrow()
1832 .as_ref()
1833 .and_then(|cache| cache.recv_ca.get(&fp).cloned())
1834 })
1835}
1836
1837#[derive(Debug, Default, Clone)]
1844pub struct WireTypeRegistry {
1845 by_id: Vec<(String, Vec<String>)>,
1846 by_fp: std::collections::HashMap<u64, u32>,
1847 enums_by_id: Vec<(String, Vec<String>)>,
1850 enums_by_name: std::collections::HashMap<String, u32>,
1851}
1852
1853impl WireTypeRegistry {
1854 pub fn new(schemas: Vec<(String, Vec<String>)>) -> Self {
1858 let mut canon: Vec<(String, Vec<String>)> = schemas
1859 .into_iter()
1860 .map(|(n, mut f)| {
1861 f.sort();
1862 (n, f)
1863 })
1864 .collect();
1865 canon.sort_by_key(|(n, f)| schema_fingerprint(n, f));
1866 canon.dedup_by_key(|(n, f)| schema_fingerprint(n, f));
1867 let by_fp = canon
1868 .iter()
1869 .enumerate()
1870 .map(|(i, (n, f))| (schema_fingerprint(n, f), i as u32))
1871 .collect();
1872 Self {
1873 by_id: canon,
1874 by_fp,
1875 ..Self::default()
1876 }
1877 }
1878
1879 pub fn with_enums(mut self, enums: Vec<(String, Vec<String>)>) -> Self {
1883 let mut canon = enums;
1884 canon.sort_by_key(|(n, c)| schema_fingerprint(n, c));
1885 canon.dedup_by_key(|(n, c)| schema_fingerprint(n, c));
1886 self.enums_by_name = canon
1887 .iter()
1888 .enumerate()
1889 .map(|(i, (n, _))| (n.clone(), i as u32))
1890 .collect();
1891 self.enums_by_id = canon;
1892 self
1893 }
1894
1895 pub fn epoch(&self) -> u64 {
1901 if self.by_id.is_empty() && self.enums_by_id.is_empty() {
1902 return 0;
1903 }
1904 let mut acc: u64 = 0xcbf2_9ce4_8422_2325;
1905 for (n, f) in &self.by_id {
1906 acc = acc.rotate_left(5) ^ schema_fingerprint(n, f);
1907 }
1908 for (n, c) in &self.enums_by_id {
1909 acc = acc.rotate_left(7) ^ schema_fingerprint(n, c).wrapping_mul(0x0000_0100_0000_01b3);
1910 }
1911 acc.max(1) }
1913
1914 fn id_of(&self, type_name: &str, field_names: &[String]) -> Option<u32> {
1915 self.by_fp
1916 .get(&schema_fingerprint(type_name, field_names))
1917 .copied()
1918 }
1919 fn schema_of(&self, id: u32) -> Option<(String, Vec<String>)> {
1920 self.by_id.get(id as usize).cloned()
1921 }
1922 fn enum_id_of(&self, type_name: &str, constructor: &str) -> Option<(u32, u32)> {
1924 let id = *self.enums_by_name.get(type_name)?;
1925 let (_, ctors) = self.enums_by_id.get(id as usize)?;
1926 let idx = ctors.iter().position(|c| c == constructor)? as u32;
1927 Some((id, idx))
1928 }
1929 fn enum_schema_of(&self, id: u32) -> Option<(String, Vec<String>)> {
1931 self.enums_by_id.get(id as usize).cloned()
1932 }
1933}
1934
1935thread_local! {
1936 static TYPE_REGISTRY: RefCell<Option<WireTypeRegistry>> = const { RefCell::new(None) };
1937}
1938
1939pub fn with_type_registry<T>(reg: WireTypeRegistry, f: impl FnOnce() -> T) -> T {
1942 struct Restore(Option<WireTypeRegistry>);
1943 impl Drop for Restore {
1944 fn drop(&mut self) {
1945 TYPE_REGISTRY.with(|c| *c.borrow_mut() = self.0.take());
1946 }
1947 }
1948 let _restore = Restore(TYPE_REGISTRY.with(|c| c.borrow_mut().replace(reg)));
1949 f()
1950}
1951
1952fn type_registry_id(type_name: &str, field_names: &[String]) -> Option<u32> {
1954 TYPE_REGISTRY.with(|c| {
1955 c.borrow()
1956 .as_ref()
1957 .and_then(|r| r.id_of(type_name, field_names))
1958 })
1959}
1960
1961fn type_registry_schema(id: u32) -> Option<(String, Vec<String>)> {
1963 TYPE_REGISTRY.with(|c| c.borrow().as_ref().and_then(|r| r.schema_of(id)))
1964}
1965
1966fn type_registry_enum_id(type_name: &str, constructor: &str) -> Option<(u32, u32)> {
1968 TYPE_REGISTRY.with(|c| {
1969 c.borrow()
1970 .as_ref()
1971 .and_then(|r| r.enum_id_of(type_name, constructor))
1972 })
1973}
1974
1975fn type_registry_enum_schema(id: u32) -> Option<(String, Vec<String>)> {
1977 TYPE_REGISTRY.with(|c| c.borrow().as_ref().and_then(|r| r.enum_schema_of(id)))
1978}
1979
1980thread_local! {
1981 static DEDUP_ENABLED: std::cell::Cell<bool> = const { std::cell::Cell::new(false) };
1987 static ENCODE_SHARED: RefCell<Option<std::collections::HashSet<usize>>> = const { RefCell::new(None) };
1990 static ENCODE_WRITTEN: RefCell<std::collections::HashMap<usize, u64>> =
1992 RefCell::new(std::collections::HashMap::new());
1993 static DECODE_MEMO: RefCell<std::collections::HashMap<u64, RuntimeValue>> =
1996 RefCell::new(std::collections::HashMap::new());
1997}
1998
1999pub fn with_dedup<T>(enabled: bool, f: impl FnOnce() -> T) -> T {
2002 let prev = DEDUP_ENABLED.with(|c| c.replace(enabled));
2003 ENCODE_SHARED.with(|c| *c.borrow_mut() = None);
2004 ENCODE_WRITTEN.with(|c| c.borrow_mut().clear());
2005 let r = f();
2006 DEDUP_ENABLED.with(|c| c.set(prev));
2007 ENCODE_SHARED.with(|c| *c.borrow_mut() = None);
2008 ENCODE_WRITTEN.with(|c| c.borrow_mut().clear());
2009 r
2010}
2011
2012fn shareable_ptr(v: &RuntimeValue) -> Option<usize> {
2016 match v {
2017 RuntimeValue::List(rc) => Some(Rc::as_ptr(rc) as *const () as usize),
2018 RuntimeValue::Tuple(rc) => Some(Rc::as_ptr(rc) as *const () as usize),
2019 RuntimeValue::Set(rc) => Some(Rc::as_ptr(rc) as *const () as usize),
2020 RuntimeValue::Map(rc) => Some(Rc::as_ptr(rc) as *const () as usize),
2021 RuntimeValue::Text(rc) => Some(Rc::as_ptr(rc) as *const () as usize),
2022 RuntimeValue::BigInt(rc) => Some(Rc::as_ptr(rc) as *const () as usize),
2023 RuntimeValue::Rational(rc) => Some(Rc::as_ptr(rc) as *const () as usize),
2024 RuntimeValue::Decimal(rc) => Some(Rc::as_ptr(rc) as *const () as usize),
2025 RuntimeValue::Money(rc) => Some(Rc::as_ptr(rc) as *const () as usize),
2026 RuntimeValue::Complex(rc) => Some(Rc::as_ptr(rc) as *const () as usize),
2027 RuntimeValue::Modular(rc) => Some(Rc::as_ptr(rc) as *const () as usize),
2028 RuntimeValue::Quantity(rc) => Some(Rc::as_ptr(rc) as *const () as usize),
2029 _ => None,
2030 }
2031}
2032
2033fn gather_shared(
2038 v: &RuntimeValue,
2039 seen: &mut std::collections::HashMap<usize, u32>,
2040 shared: &mut std::collections::HashSet<usize>,
2041 depth: u32,
2042) {
2043 if depth >= MAX_ENCODE_DEPTH {
2044 return;
2045 }
2046 if let Some(p) = shareable_ptr(v) {
2047 let c = seen.entry(p).or_insert(0);
2048 *c += 1;
2049 if *c >= 2 {
2050 shared.insert(p);
2051 return; }
2053 }
2054 match v {
2055 RuntimeValue::List(rc) => {
2056 if let ListRepr::Boxed(items) = &*rc.borrow() {
2057 for x in items {
2058 gather_shared(x, seen, shared, depth + 1);
2059 }
2060 }
2061 }
2062 RuntimeValue::Tuple(rc) => {
2063 for x in rc.iter() {
2064 gather_shared(x, seen, shared, depth + 1);
2065 }
2066 }
2067 RuntimeValue::Set(rc) => {
2068 for x in rc.borrow().iter() {
2069 gather_shared(x, seen, shared, depth + 1);
2070 }
2071 }
2072 RuntimeValue::Map(rc) => {
2073 for (k, val) in rc.borrow().iter() {
2074 gather_shared(k, seen, shared, depth + 1);
2075 gather_shared(val, seen, shared, depth + 1);
2076 }
2077 }
2078 RuntimeValue::Struct(b) => {
2079 for val in b.fields.values() {
2080 gather_shared(val, seen, shared, depth + 1);
2081 }
2082 }
2083 RuntimeValue::Inductive(b) => {
2084 for x in &b.args {
2085 gather_shared(x, seen, shared, depth + 1);
2086 }
2087 }
2088 _ => {}
2089 }
2090}
2091
2092fn value_has_sharing(v: &RuntimeValue) -> bool {
2096 let mut seen = std::collections::HashMap::new();
2097 let mut shared = std::collections::HashSet::new();
2098 gather_shared(v, &mut seen, &mut shared, 0);
2099 !shared.is_empty()
2100}
2101
2102fn dedup_encode_prefix(v: &RuntimeValue, out: &mut Vec<u8>) -> bool {
2107 if !DEDUP_ENABLED.with(|c| c.get()) {
2108 return false;
2109 }
2110 if ENCODE_SHARED.with(|c| c.borrow().is_none()) {
2111 let mut seen = std::collections::HashMap::new();
2112 let mut shared = std::collections::HashSet::new();
2113 gather_shared(v, &mut seen, &mut shared, 0);
2114 ENCODE_SHARED.with(|c| *c.borrow_mut() = Some(shared));
2115 ENCODE_WRITTEN.with(|c| c.borrow_mut().clear());
2116 }
2117 let Some(p) = shareable_ptr(v) else {
2118 return false;
2119 };
2120 let is_shared = ENCODE_SHARED.with(|c| c.borrow().as_ref().is_some_and(|s| s.contains(&p)));
2121 if !is_shared {
2122 return false;
2123 }
2124 if let Some(id) = ENCODE_WRITTEN.with(|c| c.borrow().get(&p).copied()) {
2125 out.push(T_SHARED_REF);
2126 write_uvarint(id, out);
2127 return true; }
2129 let id = ENCODE_WRITTEN.with(|c| {
2130 let mut m = c.borrow_mut();
2131 let id = m.len() as u64;
2132 m.insert(p, id);
2133 id
2134 });
2135 out.push(T_SHARED_DEF);
2136 write_uvarint(id, out);
2137 false }
2139
2140thread_local! {
2141 static STRUCT_VIEW: std::cell::Cell<bool> = const { std::cell::Cell::new(false) };
2142 static ENCODE_DEPTH: std::cell::Cell<u32> = const { std::cell::Cell::new(0) };
2146}
2147
2148const MAX_ENCODE_DEPTH: u32 = 128;
2153
2154const MAX_DECODE_BYTES: usize = 1 << 28;
2160
2161struct DepthGuard;
2164impl DepthGuard {
2165 fn enter() -> Result<DepthGuard, String> {
2166 ENCODE_DEPTH.with(|d| {
2167 let n = d.get();
2168 if n >= MAX_ENCODE_DEPTH {
2169 return Err(format!(
2170 "value nested deeper than {MAX_ENCODE_DEPTH} (cyclic or pathological) — not encodable"
2171 ));
2172 }
2173 d.set(n + 1);
2174 Ok(DepthGuard)
2175 })
2176 }
2177}
2178impl Drop for DepthGuard {
2179 fn drop(&mut self) {
2180 ENCODE_DEPTH.with(|d| d.set(d.get().saturating_sub(1)));
2181 }
2182}
2183
2184struct DecodeDepthGuard;
2190impl DecodeDepthGuard {
2191 fn enter() -> Option<DecodeDepthGuard> {
2192 DECODE_DEPTH.with(|d| {
2193 let n = d.get();
2194 if n >= receive_limits().max_depth {
2195 return None;
2196 }
2197 d.set(n + 1);
2198 Some(DecodeDepthGuard)
2199 })
2200 }
2201}
2202impl Drop for DecodeDepthGuard {
2203 fn drop(&mut self) {
2204 DECODE_DEPTH.with(|d| d.set(d.get().saturating_sub(1)));
2205 }
2206}
2207
2208pub fn with_struct_view<T>(on: bool, f: impl FnOnce() -> T) -> T {
2212 let prev = STRUCT_VIEW.with(|c| c.replace(on));
2213 let out = f();
2214 STRUCT_VIEW.with(|c| c.set(prev));
2215 out
2216}
2217
2218fn struct_view_on() -> bool {
2219 STRUCT_VIEW.with(std::cell::Cell::get)
2220}
2221
2222fn skip_str(buf: &[u8], pos: &mut usize) -> Option<()> {
2239 let n = read_uvarint(buf, pos)? as usize;
2240 let end = pos.checked_add(n)?;
2241 if end > buf.len() {
2242 return None;
2243 }
2244 *pos = end;
2245 Some(())
2246}
2247
2248pub fn peek_deferrable_sender(bytes: &[u8]) -> Option<String> {
2261 let view = view_message(bytes)?;
2262 let deferrable = view.structs_schema().is_some()
2263 || matches!(view.tag(), Some(T_INTS_ALIGNED) | Some(T_FLOATS_ALIGNED));
2264 if !deferrable {
2265 return None;
2266 }
2267 let (_, _, body) = unframe_with(bytes, false)?;
2268 let mut p = 0;
2269 read_str(body, &mut p)
2270}
2271
2272pub fn message_from_wire_view(bytes: &[u8]) -> Option<(String, RuntimeValue)> {
2273 if view_message(bytes)
2275 .and_then(|v| v.structs_schema())
2276 .is_some()
2277 {
2278 let (_, _, body) = unframe_with(bytes, false)?;
2279 let mut p = 0;
2280 let sender = read_str(body, &mut p)?; let lazy = crate::interpreter::ListRepr::from_record_list_view(Rc::new(bytes.to_vec()))?;
2282 return Some((sender, RuntimeValue::List(Rc::new(RefCell::new(lazy)))));
2283 }
2284 message_from_wire(bytes)
2285}
2286
2287const STREAM_MAGIC: u8 = 0xFD;
2291
2292pub fn frame_stream_message(from: &str, values: &[RuntimeValue]) -> Result<Vec<u8>, String> {
2298 let mut out = vec![STREAM_MAGIC];
2299 write_str(from, &mut out);
2300 for v in values {
2301 let elem = message_to_wire("", v)?;
2302 crate::concurrency::stream::frame_for_stream(&elem, &mut out);
2303 }
2304 Ok(out)
2305}
2306
2307pub fn peek_stream_sender(bytes: &[u8]) -> Option<String> {
2310 if bytes.first() != Some(&STREAM_MAGIC) {
2311 return None;
2312 }
2313 let mut p = 1;
2314 read_str(bytes, &mut p)
2315}
2316
2317pub fn deframe_stream_message(bytes: &[u8]) -> Option<Vec<RuntimeValue>> {
2320 if bytes.first() != Some(&STREAM_MAGIC) {
2321 return None;
2322 }
2323 let mut p = 1;
2324 read_str(bytes, &mut p)?;
2325 let mut deframer = crate::concurrency::stream::StreamDeframer::new();
2326 deframer.push(bytes.get(p..)?);
2327 let mut values = Vec::new();
2328 deframer.drain_frames(|frame| {
2329 if let Some((_, v)) = message_from_wire(frame) {
2330 values.push(v);
2331 }
2332 });
2333 Some(values)
2334}
2335
2336#[derive(Clone, Copy)]
2339pub struct WireView<'a> {
2340 val: &'a [u8],
2342}
2343
2344pub fn view_message(bytes: &[u8]) -> Option<WireView<'_>> {
2348 let (codec, compression, body) = unframe_with(bytes, false)?;
2353 if !matches!(codec, WireCodec::Native) || compression != WireCompression::None {
2354 return None;
2355 }
2356 let mut pos = 0;
2357 skip_str(body, &mut pos)?; Some(WireView {
2359 val: body.get(pos..)?,
2360 })
2361}
2362
2363impl<'a> WireView<'a> {
2364 fn tag(&self) -> Option<u8> {
2365 self.val.first().copied()
2366 }
2367
2368 pub fn as_int(&self) -> Option<i64> {
2370 if self.tag()? != T_INT {
2371 return None;
2372 }
2373 let mut p = 1;
2374 Some(unzigzag(read_uvarint(self.val, &mut p)?))
2375 }
2376
2377 pub fn as_float(&self) -> Option<f64> {
2379 if self.tag()? != T_FLOAT {
2380 return None;
2381 }
2382 let b = self.val.get(1..9)?;
2383 Some(f64::from_le_bytes(b.try_into().ok()?))
2384 }
2385
2386 pub fn struct_field(&self, name: &str) -> Option<WireView<'a>> {
2391 if self.tag()? != T_STRUCT_VIEW {
2392 return None;
2393 }
2394 let mut p = 1;
2395 skip_str(self.val, &mut p)?; let count = read_uvarint(self.val, &mut p)? as usize;
2397 let mut idx = None;
2398 for i in 0..count {
2399 let nlen = read_uvarint(self.val, &mut p)? as usize;
2400 let nbytes = self.val.get(p..p.checked_add(nlen)?)?;
2401 if nbytes == name.as_bytes() {
2402 idx = Some(i);
2403 }
2404 p += nlen;
2405 }
2406 let idx = idx?;
2407 let table_pos = p;
2408 let off_at = table_pos.checked_add(idx.checked_mul(4)?)?;
2409 let off_bytes = self.val.get(off_at..off_at.checked_add(4)?)?;
2410 let offset = u32::from_le_bytes(off_bytes.try_into().ok()?) as usize;
2411 let values_start = table_pos.checked_add(count.checked_mul(4)?)?;
2412 Some(WireView {
2413 val: self.val.get(values_start.checked_add(offset)?..)?,
2414 })
2415 }
2416
2417 pub fn as_i64_slice(&self) -> Option<&'a [i64]> {
2422 if self.tag()? != T_INTS_ALIGNED {
2423 return None;
2424 }
2425 let mut p = 1;
2426 let n = read_uvarint(self.val, &mut p)? as usize;
2427 let pad = *self.val.get(p)? as usize;
2428 p += 1 + pad;
2429 let nbytes = n.checked_mul(8)?;
2430 let blob = self.val.get(p..p.checked_add(nbytes)?)?;
2431 if blob.as_ptr() as usize % 8 != 0 {
2432 return None; }
2434 Some(unsafe { std::slice::from_raw_parts(blob.as_ptr().cast::<i64>(), n) })
2437 }
2438
2439 pub fn as_f64_slice(&self) -> Option<&'a [f64]> {
2443 if self.tag()? != T_FLOATS_ALIGNED {
2444 return None;
2445 }
2446 let mut p = 1;
2447 let n = read_uvarint(self.val, &mut p)? as usize;
2448 let pad = *self.val.get(p)? as usize;
2449 p += 1 + pad;
2450 let nbytes = n.checked_mul(8)?;
2451 let blob = self.val.get(p..p.checked_add(nbytes)?)?;
2452 if blob.as_ptr() as usize % 8 != 0 {
2453 return None; }
2455 Some(unsafe { std::slice::from_raw_parts(blob.as_ptr().cast::<f64>(), n) })
2458 }
2459
2460 pub fn structs_fixed_i64_col(&self, fi: usize) -> Option<&'a [u8]> {
2467 if self.tag()? != T_STRUCTS {
2468 return None;
2469 }
2470 let mut p = 1;
2471 skip_str(self.val, &mut p)?; let k = read_uvarint(self.val, &mut p)? as usize;
2473 if fi >= k {
2474 return None;
2475 }
2476 for _ in 0..k {
2477 skip_str(self.val, &mut p)?; }
2479 let n = read_uvarint(self.val, &mut p)? as usize;
2480 for c in 0..=fi {
2481 if *self.val.get(p)? != T_INTS_FIXED {
2482 return None; }
2484 p += 1;
2485 let cnt = read_uvarint(self.val, &mut p)? as usize;
2486 if cnt != n {
2487 return None;
2488 }
2489 let nbytes = n.checked_mul(8)?;
2490 let blob = self.val.get(p..p.checked_add(nbytes)?)?;
2491 if c == fi {
2492 return Some(blob);
2493 }
2494 p += nbytes;
2495 }
2496 None
2497 }
2498
2499 pub fn as_byte_slice(&self) -> Option<&'a [u8]> {
2505 if self.tag()? != T_BYTES {
2506 return None;
2507 }
2508 let mut p = 1;
2509 let n = read_uvarint(self.val, &mut p)? as usize;
2510 self.val.get(p..p.checked_add(n)?)
2511 }
2512
2513 pub fn structs_len(&self) -> Option<usize> {
2516 let tag = self.tag()?;
2517 if tag != T_STRUCTS_VIEW && tag != T_STRUCTS_FVIEW {
2518 return None;
2519 }
2520 let mut p = 1;
2521 skip_str(self.val, &mut p)?; let f = read_uvarint(self.val, &mut p)? as usize;
2523 for _ in 0..f {
2524 let nlen = read_uvarint(self.val, &mut p)? as usize;
2525 p = p.checked_add(nlen)?;
2526 }
2527 if tag == T_STRUCTS_FVIEW {
2528 p = p.checked_add(f)?; }
2530 Some(read_uvarint(self.val, &mut p)? as usize)
2531 }
2532
2533 pub fn structs_row_field(&self, row: usize, name: &str) -> Option<WireView<'a>> {
2540 if self.tag()? != T_STRUCTS_VIEW {
2541 return None;
2542 }
2543 let mut p = 1;
2544 skip_str(self.val, &mut p)?; let f = read_uvarint(self.val, &mut p)? as usize;
2546 let mut field_idx = None;
2547 for i in 0..f {
2548 let nlen = read_uvarint(self.val, &mut p)? as usize;
2549 let nbytes = self.val.get(p..p.checked_add(nlen)?)?;
2550 if nbytes == name.as_bytes() {
2551 field_idx = Some(i);
2552 }
2553 p += nlen;
2554 }
2555 let fi = field_idx?;
2556 let n = read_uvarint(self.val, &mut p)? as usize;
2557 if row >= n {
2558 return None;
2559 }
2560 let row_table_pos = p;
2561 let rows_start = row_table_pos.checked_add(n.checked_mul(4)?)?;
2562 let row_off_at = row_table_pos.checked_add(row.checked_mul(4)?)?;
2563 let row_off = u32::from_le_bytes(
2564 self.val
2565 .get(row_off_at..row_off_at.checked_add(4)?)?
2566 .try_into()
2567 .ok()?,
2568 ) as usize;
2569 let field_table_pos = rows_start.checked_add(row_off)?;
2570 let values_start = field_table_pos.checked_add(f.checked_mul(4)?)?;
2571 let field_off_at = field_table_pos.checked_add(fi.checked_mul(4)?)?;
2572 let field_off = u32::from_le_bytes(
2573 self.val
2574 .get(field_off_at..field_off_at.checked_add(4)?)?
2575 .try_into()
2576 .ok()?,
2577 ) as usize;
2578 Some(WireView {
2579 val: self.val.get(values_start.checked_add(field_off)?..)?,
2580 })
2581 }
2582
2583 pub fn structs_row_field_value(&self, row: usize, name: &str) -> Option<RuntimeValue> {
2590 match self.tag()? {
2591 T_STRUCTS_VIEW => self.structs_row_field(row, name)?.decode(),
2592 T_STRUCTS_FVIEW => {
2593 let mut p = 1;
2594 skip_str(self.val, &mut p)?; let f = read_uvarint(self.val, &mut p)? as usize;
2596 let mut field_idx = None;
2597 for i in 0..f {
2598 let nlen = read_uvarint(self.val, &mut p)? as usize;
2599 let nbytes = self.val.get(p..p.checked_add(nlen)?)?;
2600 if nbytes == name.as_bytes() {
2601 field_idx = Some(i);
2602 }
2603 p += nlen;
2604 }
2605 let fi = field_idx?;
2606 let kinds = self.val.get(p..p.checked_add(f)?)?;
2607 p += f;
2608 let n = read_uvarint(self.val, &mut p)? as usize;
2609 if row >= n {
2610 return None;
2611 }
2612 let (offsets, stride) = fview_layout(kinds);
2613 let rows_start = p;
2614 let cell_pos = rows_start
2615 .checked_add(row.checked_mul(stride)?)?
2616 .checked_add(offsets[fi])?;
2617 let mut bp = rows_start.checked_add(n.checked_mul(stride)?)?;
2619 let blob_len = read_uvarint(self.val, &mut bp)? as usize;
2620 let blob = self.val.get(bp..bp.checked_add(blob_len)?)?;
2621 fview_read_cell(kinds[fi], self.val.get(cell_pos..)?, blob)
2622 }
2623 _ => None,
2624 }
2625 }
2626
2627 pub fn decode(&self) -> Option<RuntimeValue> {
2632 let mut p = 0;
2633 native_decode(self.val, &mut p)
2634 }
2635
2636 pub fn structs_schema(&self) -> Option<(String, Vec<String>, usize)> {
2641 let tag = self.tag()?;
2642 if tag != T_STRUCTS_VIEW && tag != T_STRUCTS_FVIEW {
2643 return None;
2644 }
2645 let mut p = 1;
2646 let type_name = read_str(self.val, &mut p)?;
2647 let f = read_uvarint(self.val, &mut p)? as usize;
2648 let mut field_names = Vec::with_capacity(f.min(self.val.len().saturating_sub(p)));
2651 for _ in 0..f {
2652 field_names.push(read_str(self.val, &mut p)?);
2653 }
2654 if tag == T_STRUCTS_FVIEW {
2655 p = p.checked_add(f)?; }
2657 let n = read_uvarint(self.val, &mut p)? as usize;
2658 Some((type_name, field_names, n))
2659 }
2660
2661 pub fn as_bool(&self) -> Option<bool> {
2663 match self.tag()? {
2664 T_TRUE => Some(true),
2665 T_FALSE => Some(false),
2666 _ => None,
2667 }
2668 }
2669
2670 pub fn int_list_len(&self) -> Option<usize> {
2672 let mut p = 1;
2673 match self.tag()? {
2674 T_INTS_FIXED => Some(read_uvarint(self.val, &mut p)? as usize),
2675 T_INTS => Some((read_uvarint(self.val, &mut p)? >> 1) as usize),
2676 _ => None,
2677 }
2678 }
2679
2680 pub fn int_list_get(&self, i: usize) -> Option<i64> {
2683 match self.tag()? {
2684 T_INTS_FIXED => {
2685 let mut p = 1;
2686 let n = read_uvarint(self.val, &mut p)? as usize;
2687 if i >= n {
2688 return None;
2689 }
2690 let off = p + i * 8; let b = self.val.get(off..off + 8)?;
2692 Some(i64::from_le_bytes(b.try_into().ok()?))
2693 }
2694 T_INTS => {
2695 let mut p = 1;
2696 let header = read_uvarint(self.val, &mut p)?;
2697 let signed = header & 1 == 1;
2698 let n = (header >> 1) as usize;
2699 if i >= n {
2700 return None;
2701 }
2702 for _ in 0..i {
2703 read_uvarint(self.val, &mut p)?;
2704 }
2705 let u = read_uvarint(self.val, &mut p)?;
2706 Some(if signed { unzigzag(u) } else { u as i64 })
2707 }
2708 _ => None,
2709 }
2710 }
2711
2712 pub fn float_list_len(&self) -> Option<usize> {
2714 if self.tag()? != T_FLOATS {
2715 return None;
2716 }
2717 let mut p = 1;
2718 Some(read_uvarint(self.val, &mut p)? as usize)
2719 }
2720
2721 pub fn float_list_get(&self, i: usize) -> Option<f64> {
2723 if self.tag()? != T_FLOATS {
2724 return None;
2725 }
2726 let mut p = 1;
2727 let n = read_uvarint(self.val, &mut p)? as usize;
2728 if i >= n {
2729 return None;
2730 }
2731 let off = p + i * 8;
2732 let b = self.val.get(off..off + 8)?;
2733 Some(f64::from_le_bytes(b.try_into().ok()?))
2734 }
2735
2736 pub fn structs_cursor(&self) -> Option<WireStructsCursor<'a>> {
2741 let tag = self.tag()?;
2742 if tag != T_STRUCTS_VIEW && tag != T_STRUCTS_FVIEW {
2743 return None;
2744 }
2745 let val = self.val;
2746 let mut p = 1;
2747 let tn_len = read_uvarint(val, &mut p)? as usize; p = p.checked_add(tn_len)?;
2749 let f = read_uvarint(val, &mut p)? as usize;
2750 let mut field_names = Vec::with_capacity(f.min(val.len().saturating_sub(p)));
2752 for _ in 0..f {
2753 let nlen = read_uvarint(val, &mut p)? as usize;
2754 field_names.push(val.get(p..p.checked_add(nlen)?)?);
2755 p += nlen;
2756 }
2757 if tag == T_STRUCTS_FVIEW {
2758 let field_kinds = val.get(p..p.checked_add(f)?)?;
2759 p += f;
2760 let n = read_uvarint(val, &mut p)? as usize;
2761 let (field_offsets, stride) = fview_layout(field_kinds);
2762 let rows_start = p;
2763 let mut bp = rows_start.checked_add(n.checked_mul(stride)?)?;
2764 let blob_len = read_uvarint(val, &mut bp)? as usize;
2765 let blob = val.get(bp..bp.checked_add(blob_len)?)?;
2766 Some(WireStructsCursor {
2767 val,
2768 field_names,
2769 n,
2770 kind: CursorKind::Fixed {
2771 field_kinds,
2772 field_offsets,
2773 stride,
2774 rows_start,
2775 blob,
2776 },
2777 })
2778 } else {
2779 let n = read_uvarint(val, &mut p)? as usize;
2780 let row_table_pos = p;
2781 let rows_start = row_table_pos.checked_add(n.checked_mul(4)?)?;
2782 Some(WireStructsCursor {
2783 val,
2784 field_names,
2785 n,
2786 kind: CursorKind::Variable {
2787 row_table_pos,
2788 rows_start,
2789 },
2790 })
2791 }
2792 }
2793}
2794
2795pub struct WireStructsCursor<'a> {
2799 val: &'a [u8],
2800 field_names: Vec<&'a [u8]>,
2801 n: usize,
2802 kind: CursorKind<'a>,
2803}
2804
2805enum CursorKind<'a> {
2806 Variable {
2807 row_table_pos: usize,
2808 rows_start: usize,
2809 },
2810 Fixed {
2811 field_kinds: &'a [u8],
2812 field_offsets: Vec<usize>,
2813 stride: usize,
2814 rows_start: usize,
2815 blob: &'a [u8],
2816 },
2817}
2818
2819impl<'a> WireStructsCursor<'a> {
2820 pub fn len(&self) -> usize {
2821 self.n
2822 }
2823 pub fn is_empty(&self) -> bool {
2824 self.n == 0
2825 }
2826 pub fn field_count(&self) -> usize {
2827 self.field_names.len()
2828 }
2829 pub fn field_index(&self, name: &str) -> Option<usize> {
2831 self.field_names.iter().position(|&n| n == name.as_bytes())
2832 }
2833
2834 fn cell_slice(&self, row: usize, fi: usize) -> Option<&'a [u8]> {
2836 if row >= self.n || fi >= self.field_names.len() {
2837 return None;
2838 }
2839 match &self.kind {
2840 CursorKind::Fixed {
2841 field_offsets,
2842 stride,
2843 rows_start,
2844 ..
2845 } => {
2846 let pos = rows_start
2847 .checked_add(row.checked_mul(*stride)?)?
2848 .checked_add(field_offsets[fi])?;
2849 self.val.get(pos..)
2850 }
2851 CursorKind::Variable {
2852 row_table_pos,
2853 rows_start,
2854 } => {
2855 let f = self.field_names.len();
2856 let row_off_at = row_table_pos.checked_add(row.checked_mul(4)?)?;
2857 let row_off = u32::from_le_bytes(
2858 self.val
2859 .get(row_off_at..row_off_at.checked_add(4)?)?
2860 .try_into()
2861 .ok()?,
2862 ) as usize;
2863 let field_table_pos = rows_start.checked_add(row_off)?;
2864 let values_start = field_table_pos.checked_add(f.checked_mul(4)?)?;
2865 let field_off_at = field_table_pos.checked_add(fi.checked_mul(4)?)?;
2866 let field_off = u32::from_le_bytes(
2867 self.val
2868 .get(field_off_at..field_off_at.checked_add(4)?)?
2869 .try_into()
2870 .ok()?,
2871 ) as usize;
2872 self.val.get(values_start.checked_add(field_off)?..)
2873 }
2874 }
2875 }
2876
2877 pub fn value(&self, row: usize, fi: usize) -> Option<RuntimeValue> {
2879 match &self.kind {
2880 CursorKind::Fixed {
2881 field_kinds, blob, ..
2882 } => fview_read_cell(*field_kinds.get(fi)?, self.cell_slice(row, fi)?, blob),
2883 CursorKind::Variable { .. } => {
2884 let cell = self.cell_slice(row, fi)?;
2885 let mut q = 0;
2886 native_decode(cell, &mut q)
2887 }
2888 }
2889 }
2890
2891 pub fn i64_column(&self, fi: usize) -> Option<Vec<i64>> {
2897 let CursorKind::Fixed {
2898 field_kinds,
2899 field_offsets,
2900 stride,
2901 rows_start,
2902 ..
2903 } = &self.kind
2904 else {
2905 return None;
2906 };
2907 if *field_kinds.get(fi)? != FK_INT {
2908 return None;
2909 }
2910 let base = rows_start.checked_add(field_offsets[fi])?;
2911 let mut out = Vec::with_capacity(self.n);
2912 if self.n > 0 {
2913 let last = base.checked_add((self.n - 1).checked_mul(*stride)?)?;
2916 self.val.get(last..last.checked_add(8)?)?;
2917 let ptr = self.val.as_ptr();
2918 for r in 0..self.n {
2919 let p = base + r * stride;
2920 let b = unsafe { std::slice::from_raw_parts(ptr.add(p), 8) };
2922 out.push(i64::from_le_bytes(b.try_into().unwrap()));
2923 }
2924 }
2925 Some(out)
2926 }
2927
2928 pub fn i64(&self, row: usize, fi: usize) -> Option<i64> {
2932 let cell = self.cell_slice(row, fi)?;
2933 match &self.kind {
2934 CursorKind::Fixed { field_kinds, .. } => match *field_kinds.get(fi)? {
2935 FK_INT => Some(i64::from_le_bytes(cell.get(0..8)?.try_into().ok()?)),
2936 _ => None,
2937 },
2938 CursorKind::Variable { .. } => {
2939 if *cell.first()? != T_INT {
2940 return None;
2941 }
2942 let mut q = 1;
2943 Some(unzigzag(read_uvarint(cell, &mut q)?))
2944 }
2945 }
2946 }
2947}
2948
2949const T_NOTHING: u8 = 0;
2950const T_FALSE: u8 = 1;
2951const T_TRUE: u8 = 2;
2952const T_INT: u8 = 3;
2953const T_FLOAT: u8 = 4;
2954const T_CHAR: u8 = 5;
2955const T_TEXT: u8 = 6;
2956const T_DURATION: u8 = 7;
2957const T_DATE: u8 = 8;
2958const T_MOMENT: u8 = 9;
2959const T_SPAN: u8 = 10;
2960const T_TIME: u8 = 11;
2961const T_PEER: u8 = 12;
2962const T_LIST: u8 = 13;
2963const T_TUPLE: u8 = 14;
2964const T_SET: u8 = 15;
2965const T_MAP: u8 = 16;
2966const T_STRUCT: u8 = 17;
2967const T_INDUCTIVE: u8 = 18;
2968const 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_EXACT: u8 = 86; const T_SCALED: u8 = 87; const T_DEPENDS: u8 = 88; const T_CONVERGING: u8 = 89; const T_COMPLEXF: u8 = 85; 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 {
3036 match kind {
3037 FK_BOOL => 1,
3038 _ => 8, }
3040}
3041
3042fn fview_layout(kinds: &[u8]) -> (Vec<usize>, usize) {
3044 let mut offsets = Vec::with_capacity(kinds.len());
3045 let mut cur = 0usize;
3046 for &k in kinds {
3047 offsets.push(cur);
3048 cur += fview_width(k);
3049 }
3050 (offsets, cur)
3051}
3052
3053fn columns_fview_kinds(columns: &[ListRepr]) -> Option<Vec<u8>> {
3056 let mut kinds = Vec::with_capacity(columns.len());
3057 for col in columns {
3058 kinds.push(match col {
3059 ListRepr::Ints(_) | ListRepr::IntsI32(_) => FK_INT,
3060 ListRepr::Floats(_) => FK_FLOAT,
3061 ListRepr::Bools(_) => FK_BOOL,
3062 ListRepr::Strings { .. } => FK_TEXT,
3063 _ => return None,
3064 });
3065 }
3066 Some(kinds)
3067}
3068
3069fn fview_read_cell(kind: u8, cell: &[u8], blob: &[u8]) -> Option<RuntimeValue> {
3071 match kind {
3072 FK_INT => Some(RuntimeValue::Int(i64::from_le_bytes(
3073 cell.get(0..8)?.try_into().ok()?,
3074 ))),
3075 FK_FLOAT => Some(RuntimeValue::Float(f64::from_le_bytes(
3076 cell.get(0..8)?.try_into().ok()?,
3077 ))),
3078 FK_BOOL => Some(RuntimeValue::Bool(*cell.first()? != 0)),
3079 FK_TEXT => {
3080 let off = u32::from_le_bytes(cell.get(0..4)?.try_into().ok()?) as usize;
3081 let len = u32::from_le_bytes(cell.get(4..8)?.try_into().ok()?) as usize;
3082 let s = blob.get(off..off.checked_add(len)?)?;
3083 Some(RuntimeValue::Text(Rc::new(
3084 String::from_utf8(s.to_vec()).ok()?,
3085 )))
3086 }
3087 _ => None,
3088 }
3089}
3090const 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)]
3136pub enum WireNumerics {
3137 Varint,
3140 Fixed,
3143 GroupVarint,
3147}
3148
3149#[derive(Clone, Copy, PartialEq, Eq, Debug)]
3157pub enum WireFloats {
3158 Memcpy,
3159 XorDelta,
3160}
3161
3162#[derive(Clone, Copy, PartialEq, Eq, Debug)]
3169pub enum WireStructure {
3170 Off,
3172 Affine,
3177 Auto,
3185}
3186
3187thread_local! {
3188 static NUMERICS: std::cell::Cell<WireNumerics> = const { std::cell::Cell::new(WireNumerics::Varint) };
3189 static FLOATS: std::cell::Cell<WireFloats> = const { std::cell::Cell::new(WireFloats::Memcpy) };
3190 static STRUCTURE: std::cell::Cell<WireStructure> = const { std::cell::Cell::new(WireStructure::Off) };
3191 static FLAT_LISTS: std::cell::Cell<bool> = const { std::cell::Cell::new(false) };
3196}
3197
3198pub fn with_flat_lists<T>(on: bool, f: impl FnOnce() -> T) -> T {
3200 let prev = FLAT_LISTS.with(|c| c.replace(on));
3201 let out = f();
3202 FLAT_LISTS.with(|c| c.set(prev));
3203 out
3204}
3205
3206#[inline]
3207fn flat_lists() -> bool {
3208 FLAT_LISTS.with(|c| c.get())
3209}
3210
3211pub fn with_numerics<T>(n: WireNumerics, f: impl FnOnce() -> T) -> T {
3213 let prev = NUMERICS.with(|c| c.replace(n));
3214 let out = f();
3215 NUMERICS.with(|c| c.set(prev));
3216 out
3217}
3218
3219pub fn with_fixed_numerics<T>(f: impl FnOnce() -> T) -> T {
3221 with_numerics(WireNumerics::Fixed, f)
3222}
3223
3224fn numerics() -> WireNumerics {
3225 NUMERICS.with(std::cell::Cell::get)
3226}
3227
3228pub fn with_structure<T>(s: WireStructure, f: impl FnOnce() -> T) -> T {
3231 let prev = STRUCTURE.with(|c| c.replace(s));
3232 let out = f();
3233 STRUCTURE.with(|c| c.set(prev));
3234 out
3235}
3236
3237fn structure() -> WireStructure {
3238 STRUCTURE.with(std::cell::Cell::get)
3239}
3240
3241const PERIOD_CAP: usize = 512;
3244
3245pub(crate) fn lower_expr_to_genexpr(
3251 e: &crate::ast::stmt::Expr<'_>,
3252 param: logicaffeine_base::Symbol,
3253) -> Option<GenExpr> {
3254 use crate::ast::stmt::{BinaryOpKind, Expr, Literal};
3255 match e {
3256 Expr::Literal(Literal::Number(n)) => Some(GenExpr::Const(*n)),
3257 Expr::Identifier(s) if *s == param => Some(GenExpr::Index),
3258 Expr::BinaryOp { op, left, right } => {
3259 let l = Box::new(lower_expr_to_genexpr(left, param)?);
3260 let r = Box::new(lower_expr_to_genexpr(right, param)?);
3261 Some(match op {
3262 BinaryOpKind::Add => GenExpr::Add(l, r),
3263 BinaryOpKind::Subtract => GenExpr::Sub(l, r),
3264 BinaryOpKind::Multiply => GenExpr::Mul(l, r),
3265 BinaryOpKind::Divide => GenExpr::Div(l, r),
3266 BinaryOpKind::Modulo => GenExpr::Mod(l, r),
3267 _ => return None,
3268 })
3269 }
3270 _ => None,
3271 }
3272}
3273
3274fn bitpack(vals: &[u64], width: u8) -> Vec<u8> {
3276 if width == 0 {
3277 return Vec::new();
3278 }
3279 let total_bits = vals.len().saturating_mul(width as usize);
3280 let mut out = vec![0u8; total_bits.div_ceil(8)];
3281 let mut bitpos = 0usize;
3282 for &val in vals {
3283 let mut bits = val;
3284 let mut remaining = width as usize;
3285 while remaining > 0 {
3286 let byte = bitpos / 8;
3287 let off = bitpos % 8;
3288 let take = remaining.min(8 - off);
3289 let mask = (1u64 << take) - 1;
3290 out[byte] |= ((bits & mask) as u8) << off;
3291 bits >>= take;
3292 bitpos += take;
3293 remaining -= take;
3294 }
3295 }
3296 out
3297}
3298
3299fn bitunpack(bytes: &[u8], count: usize, width: u8) -> Option<Vec<u64>> {
3302 if width == 0 || width > 64 {
3303 return None;
3304 }
3305 let total_bits = count.checked_mul(width as usize)?;
3306 if bytes.len() < total_bits.div_ceil(8) {
3307 return None;
3308 }
3309 let mut out = Vec::with_capacity(count.min(PREALLOC_CAP));
3310 let mut bitpos = 0usize;
3311 for _ in 0..count {
3312 let mut val = 0u64;
3313 let mut got = 0usize;
3314 while got < width as usize {
3315 let byte = bitpos / 8;
3316 let off = bitpos % 8;
3317 let take = (width as usize - got).min(8 - off);
3318 let mask = (1u64 << take) - 1;
3319 val |= (((bytes[byte] >> off) as u64) & mask) << got;
3320 got += take;
3321 bitpos += take;
3322 }
3323 out.push(val);
3324 }
3325 Some(out)
3326}
3327
3328pub fn with_floats<T>(mode: WireFloats, f: impl FnOnce() -> T) -> T {
3330 let prev = FLOATS.with(|c| c.replace(mode));
3331 let out = f();
3332 FLOATS.with(|c| c.set(prev));
3333 out
3334}
3335
3336fn floats_mode() -> WireFloats {
3337 FLOATS.with(std::cell::Cell::get)
3338}
3339
3340fn detect_float_const(v: &[f64]) -> Option<u64> {
3345 let bits = canonical_f64_bits(*v.first()?);
3346 v.iter().all(|x| canonical_f64_bits(*x) == bits).then_some(bits)
3347}
3348
3349fn detect_float_affine(v: &[f64]) -> Option<(f64, f64)> {
3355 if v.len() < 3 {
3356 return None;
3357 }
3358 let base = v[0];
3359 let stride = v[1] - v[0];
3360 for (i, &x) in v.iter().enumerate() {
3361 if canonical_f64_bits(base + (i as f64) * stride) != canonical_f64_bits(x) {
3362 return None;
3363 }
3364 }
3365 Some((base, stride))
3366}
3367
3368fn detect_float_sparse(v: &[f64]) -> Option<(u64, Vec<(usize, u64)>)> {
3373 if v.len() < 8 {
3374 return None;
3375 }
3376 let mut cand = canonical_f64_bits(v[0]);
3377 let mut count: i64 = 0;
3378 for x in v {
3379 let b = canonical_f64_bits(*x);
3380 if count == 0 {
3381 cand = b;
3382 count = 1;
3383 } else if b == cand {
3384 count += 1;
3385 } else {
3386 count -= 1;
3387 }
3388 }
3389 let occ = v.iter().filter(|x| canonical_f64_bits(**x) == cand).count();
3390 if v.len() - occ > v.len() / 4 {
3391 return None;
3392 }
3393 let exceptions: Vec<(usize, u64)> = v
3394 .iter()
3395 .enumerate()
3396 .filter(|(_, x)| canonical_f64_bits(**x) != cand)
3397 .map(|(i, x)| (i, canonical_f64_bits(*x)))
3398 .collect();
3399 Some((cand, exceptions))
3400}
3401
3402fn detect_float_period(v: &[f64]) -> Option<usize> {
3406 let n = v.len();
3407 if n < 4 {
3408 return None;
3409 }
3410 let cap = (n / 2).min(PERIOD_CAP);
3411 'p: for p in 2..=cap {
3412 for i in p..n {
3413 if canonical_f64_bits(v[i]) != canonical_f64_bits(v[i - p]) {
3414 continue 'p;
3415 }
3416 }
3417 return Some(p);
3418 }
3419 None
3420}
3421
3422fn detect_float_geometric(v: &[f64]) -> Option<(f64, f64)> {
3427 if v.len() < 3 {
3428 return None;
3429 }
3430 let base = v[0];
3431 if base == 0.0 || !base.is_finite() {
3432 return None;
3433 }
3434 let ratio = v[1] / base;
3435 if !ratio.is_finite() || ratio == 1.0 {
3436 return None; }
3438 let mut cur = base;
3439 for &x in v {
3440 if canonical_f64_bits(cur) != canonical_f64_bits(x) {
3441 return None;
3442 }
3443 cur *= ratio;
3444 }
3445 Some((base, ratio))
3446}
3447
3448fn floats_xor_encode(out: &mut Vec<u8>, v: &[f64]) {
3451 write_uvarint(v.len() as u64, out);
3452 let mut prev = 0u64;
3453 for &f in v {
3454 let bits = canonical_f64_bits(f);
3455 write_uvarint(bits ^ prev, out);
3456 prev = bits;
3457 }
3458}
3459
3460fn uvarint_byte_len(x: u64) -> usize {
3462 (((64 - x.leading_zeros()).max(1) + 6) / 7) as usize
3463}
3464
3465fn floats_memcpy_body_len(n: usize) -> usize {
3468 uvarint_byte_len(n as u64) + n * 8
3469}
3470
3471#[derive(Clone, Copy, PartialEq, Eq, Debug)]
3476pub enum WireCompression {
3477 None,
3480 Deflate,
3482 Lz4,
3485 Zstd,
3488}
3489
3490fn compression_id(c: WireCompression) -> u8 {
3493 match c {
3494 WireCompression::None | WireCompression::Deflate => 0,
3495 WireCompression::Lz4 => 1,
3496 WireCompression::Zstd => 2,
3497 }
3498}
3499
3500#[derive(Clone, Copy, PartialEq, Eq, Debug)]
3504pub enum WireCompressionLevel {
3505 Fast,
3506 Balanced,
3507 Max,
3508}
3509
3510thread_local! {
3511 static COMPRESSION_CODEC: std::cell::Cell<WireCompression> =
3512 const { std::cell::Cell::new(WireCompression::None) };
3513 static COMPRESSION_LEVEL: std::cell::Cell<WireCompressionLevel> =
3514 const { std::cell::Cell::new(WireCompressionLevel::Balanced) };
3515}
3516
3517pub fn with_compression_codec<T>(codec: WireCompression, f: impl FnOnce() -> T) -> T {
3520 let prev = COMPRESSION_CODEC.with(|c| c.replace(codec));
3521 let out = f();
3522 COMPRESSION_CODEC.with(|c| c.set(prev));
3523 out
3524}
3525
3526pub fn with_compression_level<T>(level: WireCompressionLevel, f: impl FnOnce() -> T) -> T {
3528 let prev = COMPRESSION_LEVEL.with(|c| c.replace(level));
3529 let out = f();
3530 COMPRESSION_LEVEL.with(|c| c.set(prev));
3531 out
3532}
3533
3534fn compression_level() -> WireCompressionLevel {
3535 COMPRESSION_LEVEL.with(std::cell::Cell::get)
3536}
3537
3538fn deflate_level() -> u8 {
3540 match compression_level() {
3541 WireCompressionLevel::Fast => 1,
3542 WireCompressionLevel::Balanced => 6,
3543 WireCompressionLevel::Max => 9,
3544 }
3545}
3546
3547#[cfg(not(target_arch = "wasm32"))]
3550fn zstd_level() -> i32 {
3551 match compression_level() {
3552 WireCompressionLevel::Fast => 1,
3553 WireCompressionLevel::Balanced => 9,
3554 WireCompressionLevel::Max => 19,
3555 }
3556}
3557
3558pub fn with_compression<T>(f: impl FnOnce() -> T) -> T {
3561 with_compression_codec(WireCompression::Deflate, f)
3562}
3563
3564fn compression_codec() -> WireCompression {
3565 COMPRESSION_CODEC.with(std::cell::Cell::get)
3566}
3567
3568fn compress_body(codec: WireCompression, body: &[u8]) -> Option<(WireCompression, Vec<u8>)> {
3572 match codec {
3573 WireCompression::None => None,
3574 WireCompression::Deflate => Some((
3575 codec,
3576 miniz_oxide::deflate::compress_to_vec(body, deflate_level()),
3577 )),
3578 WireCompression::Lz4 => Some((codec, lz4_flex::compress_prepend_size(body))),
3579 WireCompression::Zstd => {
3580 #[cfg(not(target_arch = "wasm32"))]
3581 {
3582 zstd::encode_all(body, zstd_level())
3583 .ok()
3584 .map(|z| (WireCompression::Zstd, z))
3585 }
3586 #[cfg(target_arch = "wasm32")]
3587 {
3588 Some((WireCompression::Lz4, lz4_flex::compress_prepend_size(body)))
3591 }
3592 }
3593 }
3594}
3595
3596pub fn best_compressed_len(body: &[u8]) -> usize {
3602 [
3603 WireCompression::Deflate,
3604 WireCompression::Lz4,
3605 WireCompression::Zstd,
3606 ]
3607 .into_iter()
3608 .filter_map(|c| compress_body(c, body).map(|(_, z)| z.len()))
3609 .fold(body.len(), usize::min)
3610}
3611
3612pub fn compress_best(body: &[u8]) -> Vec<u8> {
3619 let mut best_tag = 3u8; let mut best_body: Vec<u8> = body.to_vec();
3621 for codec in [
3622 WireCompression::Deflate,
3623 WireCompression::Lz4,
3624 WireCompression::Zstd,
3625 ] {
3626 if let Some((used, z)) = compress_body(codec, body) {
3627 if z.len() < best_body.len() {
3628 best_tag = compression_id(used); best_body = z;
3630 }
3631 }
3632 }
3633 let mut out = Vec::with_capacity(best_body.len() + 1);
3634 out.push(best_tag);
3635 out.extend_from_slice(&best_body);
3636 out
3637}
3638
3639pub fn decompress_any(frame: &[u8]) -> Option<Vec<u8>> {
3642 let (&tag, body) = frame.split_first()?;
3643 let codec = match tag {
3644 0 => WireCompression::Deflate,
3645 1 => WireCompression::Lz4,
3646 2 => WireCompression::Zstd,
3647 3 => return Some(body.to_vec()), _ => return None,
3649 };
3650 decompress_body(codec, body)
3651}
3652
3653fn decompress_body(codec: WireCompression, body: &[u8]) -> Option<Vec<u8>> {
3655 match codec {
3656 WireCompression::None => Some(body.to_vec()),
3657 WireCompression::Deflate => {
3660 miniz_oxide::inflate::decompress_to_vec_with_limit(body, MAX_DECODE_BYTES).ok()
3661 }
3662 WireCompression::Lz4 => {
3663 if body.len() < 4 {
3666 return None;
3667 }
3668 let claimed = u32::from_le_bytes([body[0], body[1], body[2], body[3]]) as usize;
3669 if claimed > MAX_DECODE_BYTES {
3670 return None;
3671 }
3672 lz4_flex::decompress_size_prepended(body).ok()
3673 }
3674 WireCompression::Zstd => {
3675 #[cfg(not(target_arch = "wasm32"))]
3676 {
3677 use std::io::Read;
3678 let mut out = Vec::new();
3681 let dec = zstd::stream::read::Decoder::new(body).ok()?;
3682 dec.take(MAX_DECODE_BYTES as u64 + 1)
3683 .read_to_end(&mut out)
3684 .ok()?;
3685 if out.len() > MAX_DECODE_BYTES {
3686 return None;
3687 }
3688 Some(out)
3689 }
3690 #[cfg(target_arch = "wasm32")]
3691 {
3692 zstd_decode_ruzstd(body)
3693 }
3694 }
3695 }
3696}
3697
3698fn zstd_decode_ruzstd(body: &[u8]) -> Option<Vec<u8>> {
3701 use std::io::Read;
3702 let mut dec = ruzstd::StreamingDecoder::new(body).ok()?;
3703 let mut out = Vec::new();
3704 dec.read_to_end(&mut out).ok()?;
3705 Some(out)
3706}
3707
3708#[inline]
3717fn gv_code(zz: u64) -> u8 {
3718 if zz <= 0xFF {
3719 0
3720 } else if zz <= 0xFFFF {
3721 1
3722 } else if zz <= 0xFFFF_FFFF {
3723 2
3724 } else {
3725 3
3726 }
3727}
3728
3729fn leb128_encode<I: Iterator<Item = i64> + Clone>(out: &mut Vec<u8>, vals: I, n: usize) {
3740 let signed = vals.clone().any(|x| x < 0);
3741 write_uvarint(((n as u64) << 1) | signed as u64, out);
3742 out.reserve(n * 2);
3743 if signed {
3744 for x in vals {
3745 write_uvarint(zigzag(x), out);
3746 }
3747 } else {
3748 for x in vals {
3749 write_uvarint(x as u64, out);
3750 }
3751 }
3752}
3753
3754fn fixed_encode_i64(out: &mut Vec<u8>, v: &[i64]) {
3757 write_uvarint(v.len() as u64, out);
3758 #[cfg(target_endian = "little")]
3759 {
3760 let bytes = unsafe {
3762 std::slice::from_raw_parts(v.as_ptr().cast::<u8>(), std::mem::size_of_val(v))
3763 };
3764 out.extend_from_slice(bytes);
3765 }
3766 #[cfg(target_endian = "big")]
3767 {
3768 out.reserve(v.len() * 8);
3769 for &n in v {
3770 out.extend_from_slice(&n.to_le_bytes());
3771 }
3772 }
3773}
3774
3775fn gv_encode<I: Iterator<Item = i64> + Clone>(out: &mut Vec<u8>, vals: I, n: usize) {
3776 write_uvarint(n as u64, out);
3777 let control_at = out.len();
3778 out.resize(control_at + n.div_ceil(4), 0);
3779 out.reserve(n * 2);
3780 for (i, x) in vals.enumerate() {
3781 let zz = zigzag(x);
3782 let code = gv_code(zz);
3783 out[control_at + (i >> 2)] |= code << ((i & 3) * 2);
3784 out.extend_from_slice(&zz.to_le_bytes()[..1usize << code]);
3785 }
3786}
3787
3788fn gv_decode(buf: &[u8], pos: &mut usize) -> Option<Vec<i64>> {
3789 let n = read_uvarint(buf, pos)? as usize;
3790 let control_len = n.div_ceil(4);
3791 let control = buf.get(*pos..pos.checked_add(control_len)?)?;
3792 let mut dpos = *pos + control_len;
3793 let len = buf.len();
3794 let mut v = Vec::with_capacity(n.min(PREALLOC_CAP));
3795 for i in 0..n {
3796 let code = (control[i >> 2] >> ((i & 3) * 2)) & 0x3;
3797 let width = 1usize << code;
3798 let zz = if dpos + 8 <= len {
3799 let word = u64::from_le_bytes(buf[dpos..dpos + 8].try_into().unwrap());
3802 let mask = if width == 8 {
3803 u64::MAX
3804 } else {
3805 (1u64 << (width * 8)) - 1
3806 };
3807 word & mask
3808 } else {
3809 let raw = buf.get(dpos..dpos.checked_add(width)?)?;
3811 let mut b = [0u8; 8];
3812 b[..width].copy_from_slice(raw);
3813 u64::from_le_bytes(b)
3814 };
3815 dpos += width;
3816 v.push(unzigzag(zz));
3817 }
3818 *pos = dpos;
3819 Some(v)
3820}
3821
3822fn gv_decode_dispatch(buf: &[u8], pos: &mut usize) -> Option<Vec<i64>> {
3826 #[cfg(target_arch = "x86_64")]
3827 {
3828 if is_x86_feature_detected!("ssse3") {
3829 return unsafe { gv_decode_ssse3(buf, pos) };
3831 }
3832 }
3833 gv_decode(buf, pos)
3834}
3835
3836#[cfg(target_arch = "x86_64")]
3841fn gv_shuffle_masks() -> &'static [[u8; 16]; 16] {
3842 use std::sync::OnceLock;
3843 static MASKS: OnceLock<[[u8; 16]; 16]> = OnceLock::new();
3844 MASKS.get_or_init(|| {
3845 let mut m = [[0x80u8; 16]; 16];
3846 for ca in 0..4usize {
3847 for cb in 0..4usize {
3848 let (wa, wb) = (1usize << ca, 1usize << cb);
3849 let entry = &mut m[(ca << 2) | cb];
3850 for j in 0..wa {
3851 entry[j] = j as u8;
3852 }
3853 for k in 0..wb {
3854 entry[8 + k] = (wa + k) as u8;
3855 }
3856 }
3857 }
3858 m
3859 })
3860}
3861
3862#[cfg(target_arch = "x86_64")]
3868#[target_feature(enable = "ssse3")]
3869unsafe fn gv_decode_ssse3(buf: &[u8], pos: &mut usize) -> Option<Vec<i64>> {
3870 use std::arch::x86_64::*;
3871 let n = read_uvarint(buf, pos)? as usize;
3872 let control_len = n.div_ceil(4);
3873 let control = buf.get(*pos..pos.checked_add(control_len)?)?;
3874 let mut dpos = *pos + control_len;
3875 let len = buf.len();
3876 let mut v = Vec::with_capacity(n.min(PREALLOC_CAP));
3877 let masks = gv_shuffle_masks();
3878 let mut i = 0;
3879 while i + 2 <= n && dpos + 16 <= len {
3880 let ctrl = control[i >> 2];
3881 let ca = ((ctrl >> ((i & 3) * 2)) & 0x3) as usize;
3882 let cb = ((ctrl >> (((i + 1) & 3) * 2)) & 0x3) as usize;
3883 let data = _mm_loadu_si128(buf.as_ptr().add(dpos).cast());
3884 let mask = _mm_loadu_si128(masks[(ca << 2) | cb].as_ptr().cast());
3885 let out = _mm_shuffle_epi8(data, mask);
3886 let mut tmp = [0u8; 16];
3887 _mm_storeu_si128(tmp.as_mut_ptr().cast(), out);
3888 v.push(unzigzag(u64::from_le_bytes(tmp[0..8].try_into().unwrap())));
3889 v.push(unzigzag(u64::from_le_bytes(tmp[8..16].try_into().unwrap())));
3890 dpos += (1usize << ca) + (1usize << cb);
3891 i += 2;
3892 }
3893 while i < n {
3894 let code = (control[i >> 2] >> ((i & 3) * 2)) & 0x3;
3895 let width = 1usize << code;
3896 let raw = buf.get(dpos..dpos.checked_add(width)?)?;
3897 let mut b = [0u8; 8];
3898 b[..width].copy_from_slice(raw);
3899 v.push(unzigzag(u64::from_le_bytes(b)));
3900 dpos += width;
3901 i += 1;
3902 }
3903 *pos = dpos;
3904 Some(v)
3905}
3906
3907#[inline]
3908fn write_uvarint(mut x: u64, out: &mut Vec<u8>) {
3909 while x >= 0x80 {
3910 out.push((x as u8) | 0x80);
3911 x >>= 7;
3912 }
3913 out.push(x as u8);
3914}
3915
3916#[inline]
3917fn read_uvarint(buf: &[u8], pos: &mut usize) -> Option<u64> {
3918 let mut result = 0u64;
3919 let mut shift = 0u32;
3920 loop {
3921 let b = *buf.get(*pos)?;
3922 *pos += 1;
3923 if shift >= 64 {
3924 return None; }
3926 result |= u64::from(b & 0x7f) << shift;
3927 if b & 0x80 == 0 {
3928 return Some(result);
3929 }
3930 shift += 7;
3931 }
3932}
3933
3934#[inline]
3935fn zigzag(x: i64) -> u64 {
3936 ((x << 1) ^ (x >> 63)) as u64
3937}
3938
3939#[inline]
3940fn unzigzag(x: u64) -> i64 {
3941 ((x >> 1) as i64) ^ -((x & 1) as i64)
3942}
3943
3944#[inline]
3945fn write_str(s: &str, out: &mut Vec<u8>) {
3946 write_uvarint(s.len() as u64, out);
3947 out.extend_from_slice(s.as_bytes());
3948}
3949
3950#[inline]
3951fn read_str(buf: &[u8], pos: &mut usize) -> Option<String> {
3952 let n = read_uvarint(buf, pos)? as usize;
3953 let bytes = buf.get(*pos..pos.checked_add(n)?)?;
3954 *pos += n;
3955 String::from_utf8(bytes.to_vec()).ok()
3956}
3957
3958fn dict_encode_strings(data: &[u8], ends: &[u32]) -> Vec<u8> {
3965 let n = ends.len();
3966 let mut dict: Vec<&[u8]> = Vec::new();
3967 let mut index_of: std::collections::HashMap<&[u8], u64> = std::collections::HashMap::new();
3968 let mut indices: Vec<u64> = Vec::with_capacity(n);
3969 let mut prev = 0u32;
3970 for &e in ends {
3971 let s = &data[prev as usize..e as usize];
3972 prev = e;
3973 let idx = *index_of.entry(s).or_insert_with(|| {
3974 dict.push(s);
3975 (dict.len() - 1) as u64
3976 });
3977 indices.push(idx);
3978 }
3979 let mut out = vec![T_STRINGS_DICT];
3980 write_uvarint(dict.len() as u64, &mut out);
3981 for d in &dict {
3982 write_uvarint(d.len() as u64, &mut out);
3983 out.extend_from_slice(d);
3984 }
3985 write_uvarint(n as u64, &mut out);
3986 let iw = if dict.len() <= 1 {
3987 0
3988 } else {
3989 (64 - ((dict.len() - 1) as u64).leading_zeros()) as u8
3990 };
3991 out.push(iw);
3992 if iw > 0 {
3993 out.extend_from_slice(&bitpack(&indices, iw));
3994 }
3995 out
3996}
3997
3998fn string_slices<'a>(data: &'a [u8], ends: &[u32]) -> Vec<&'a [u8]> {
4002 let mut out = Vec::with_capacity(ends.len());
4003 let mut prev = 0usize;
4004 for &e in ends {
4005 out.push(&data[prev..e as usize]);
4006 prev = e as usize;
4007 }
4008 out
4009}
4010
4011fn try_template_encode(data: &[u8], ends: &[u32]) -> Option<Vec<u8>> {
4017 let n = ends.len();
4018 if n < 3 {
4019 return None;
4020 }
4021 let strs = string_slices(data, ends);
4022 let first = strs[0];
4023 let mut prefix_len = first.len();
4025 for s in &strs[1..] {
4026 let lim = prefix_len.min(s.len());
4027 let mut i = 0;
4028 while i < lim && first[i] == s[i] {
4029 i += 1;
4030 }
4031 prefix_len = i;
4032 }
4033 let mut suffix_len = first.len() - prefix_len;
4035 for s in &strs[1..] {
4036 let lim = suffix_len.min(s.len() - prefix_len);
4037 let mut i = 0;
4038 while i < lim && first[first.len() - 1 - i] == s[s.len() - 1 - i] {
4039 i += 1;
4040 }
4041 suffix_len = i;
4042 }
4043 let mut nums = Vec::with_capacity(n);
4045 for s in &strs {
4046 let mid = &s[prefix_len..s.len() - suffix_len];
4047 let mid_str = std::str::from_utf8(mid).ok()?;
4048 let num: i64 = mid_str.parse().ok()?;
4049 if num.to_string().as_bytes() != mid {
4050 return None;
4051 }
4052 nums.push(num);
4053 }
4054 let (base, stride) = detect_affine(&nums)?;
4055 let mut c = vec![T_STRINGS_TEMPLATE];
4056 write_uvarint(prefix_len as u64, &mut c);
4057 c.extend_from_slice(&first[..prefix_len]);
4058 write_uvarint(suffix_len as u64, &mut c);
4059 c.extend_from_slice(&first[first.len() - suffix_len..]);
4060 write_uvarint(zigzag(base), &mut c);
4061 write_uvarint(zigzag(stride), &mut c);
4062 write_uvarint(n as u64, &mut c);
4063 Some(c)
4064}
4065
4066fn front_code_strings(data: &[u8], ends: &[u32]) -> Vec<u8> {
4074 let strs = string_slices(data, ends);
4075 let mut out = vec![T_STRINGS_FRONT];
4076 write_uvarint(strs.len() as u64, &mut out);
4077 let mut prev: &[u8] = &[];
4078 for s in &strs {
4079 let lim = prev.len().min(s.len());
4080 let mut common = 0usize;
4081 while common < lim && prev[common] == s[common] {
4082 common += 1;
4083 }
4084 while common > 0 && common < s.len() && (s[common] & 0xC0) == 0x80 {
4086 common -= 1;
4087 }
4088 write_uvarint(common as u64, &mut out);
4089 write_uvarint((s.len() - common) as u64, &mut out);
4090 out.extend_from_slice(&s[common..]);
4091 prev = s;
4092 }
4093 out
4094}
4095
4096fn bool_bitpack(v: &[bool], out: &mut Vec<u8>) {
4098 out.push(T_BOOLS);
4099 write_uvarint(v.len() as u64, out);
4100 let mut cur = 0u8;
4101 let mut nbits = 0u8;
4102 for &b in v {
4103 cur |= u8::from(b) << nbits;
4104 nbits += 1;
4105 if nbits == 8 {
4106 out.push(cur);
4107 cur = 0;
4108 nbits = 0;
4109 }
4110 }
4111 if nbits > 0 {
4112 out.push(cur);
4113 }
4114}
4115
4116const BOOL_PERIOD_CAP: usize = 256;
4119
4120fn detect_bool_period(v: &[bool]) -> Option<usize> {
4123 let n = v.len();
4124 let cap = (n / 2).min(BOOL_PERIOD_CAP);
4125 'p: for p in 1..=cap {
4126 for i in p..n {
4127 if v[i] != v[i - p] {
4128 continue 'p;
4129 }
4130 }
4131 return Some(p);
4132 }
4133 None
4134}
4135
4136fn bool_periodic_encode(v: &[bool], p: usize) -> Vec<u8> {
4138 let mut c = vec![T_BOOLS_PERIODIC];
4139 write_uvarint(p as u64, &mut c);
4140 write_uvarint(v.len() as u64, &mut c);
4141 let mut cur = 0u8;
4142 let mut nbits = 0u8;
4143 for &b in &v[..p] {
4144 cur |= u8::from(b) << nbits;
4145 nbits += 1;
4146 if nbits == 8 {
4147 c.push(cur);
4148 cur = 0;
4149 nbits = 0;
4150 }
4151 }
4152 if nbits > 0 {
4153 c.push(cur);
4154 }
4155 c
4156}
4157
4158fn bool_rle_encode(v: &[bool]) -> Vec<u8> {
4162 let mut c = vec![T_BOOLS_RLE];
4163 write_uvarint(v.len() as u64, &mut c);
4164 if v.is_empty() {
4165 c.push(0); write_uvarint(0, &mut c);
4167 return c;
4168 }
4169 c.push(v[0] as u8);
4170 let mut runs: Vec<u64> = Vec::new();
4171 let mut cur = v[0];
4172 let mut len = 0u64;
4173 for &b in v {
4174 if b == cur {
4175 len += 1;
4176 } else {
4177 runs.push(len);
4178 cur = b;
4179 len = 1;
4180 }
4181 }
4182 runs.push(len);
4183 write_uvarint(runs.len() as u64, &mut c);
4184 for r in runs {
4185 write_uvarint(r, &mut c);
4186 }
4187 c
4188}
4189
4190fn emit_best_bool_column(v: &[bool], out: &mut Vec<u8>) {
4191 let mut best = Vec::new();
4192 bool_bitpack(v, &mut best);
4193 if let Some(p) = detect_bool_period(v) {
4194 consider(&mut best, bool_periodic_encode(v, p));
4195 }
4196 consider(&mut best, bool_rle_encode(v));
4197 out.extend_from_slice(&best);
4198}
4199
4200fn common_affix_lens(strs: &[&[u8]]) -> (usize, usize) {
4204 let first = strs[0];
4205 let mut prefix_len = first.len();
4206 for s in &strs[1..] {
4207 let lim = prefix_len.min(s.len());
4208 let mut i = 0;
4209 while i < lim && first[i] == s[i] {
4210 i += 1;
4211 }
4212 prefix_len = i;
4213 }
4214 while prefix_len > 0 && prefix_len < first.len() && (first[prefix_len] & 0xC0) == 0x80 {
4215 prefix_len -= 1;
4216 }
4217 let mut suffix_len = first.len() - prefix_len;
4218 for s in &strs[1..] {
4219 let lim = suffix_len.min(s.len() - prefix_len);
4220 let mut i = 0;
4221 while i < lim && first[first.len() - 1 - i] == s[s.len() - 1 - i] {
4222 i += 1;
4223 }
4224 suffix_len = i;
4225 }
4226 while suffix_len > 0 && (first[first.len() - suffix_len] & 0xC0) == 0x80 {
4227 suffix_len -= 1;
4228 }
4229 (prefix_len, suffix_len)
4230}
4231
4232fn try_affix_encode(data: &[u8], ends: &[u32]) -> Option<Vec<u8>> {
4238 let n = ends.len();
4239 if n < 2 {
4240 return None;
4241 }
4242 let strs = string_slices(data, ends);
4243 let (prefix_len, suffix_len) = common_affix_lens(&strs);
4244 if prefix_len + suffix_len == 0 {
4245 return None;
4246 }
4247 let first = strs[0];
4248 let mut c = vec![T_STRINGS_AFFIX];
4249 write_uvarint(prefix_len as u64, &mut c);
4250 c.extend_from_slice(&first[..prefix_len]);
4251 write_uvarint(suffix_len as u64, &mut c);
4252 c.extend_from_slice(&first[first.len() - suffix_len..]);
4253 write_uvarint(n as u64, &mut c);
4254 for s in &strs {
4255 let mid = &s[prefix_len..s.len() - suffix_len];
4256 write_uvarint(mid.len() as u64, &mut c);
4257 c.extend_from_slice(mid);
4258 }
4259 Some(c)
4260}
4261
4262fn emit_best_string_column(data: &[u8], ends: &[u32], out: &mut Vec<u8>) {
4263 let mut best = Vec::new();
4264 write_string_array_from_ends(&mut best, data, ends);
4265 consider(&mut best, dict_encode_strings(data, ends));
4266 consider(&mut best, front_code_strings(data, ends));
4267 if let Some(tpl) = try_template_encode(data, ends) {
4268 consider(&mut best, tpl);
4269 }
4270 if let Some(affix) = try_affix_encode(data, ends) {
4271 consider(&mut best, affix);
4272 }
4273 out.extend_from_slice(&best);
4274}
4275
4276fn write_string_array_from_ends(out: &mut Vec<u8>, data: &[u8], ends: &[u32]) {
4277 out.push(T_STRINGS);
4278 write_uvarint(ends.len() as u64, out);
4279 let mut prev = 0u32;
4280 for &e in ends {
4281 write_uvarint(u64::from(e - prev), out);
4282 prev = e;
4283 }
4284 out.extend_from_slice(data);
4285}
4286
4287fn struct_schema(v: &[RuntimeValue]) -> Option<(String, Vec<String>)> {
4293 let first = match v.first()? {
4294 RuntimeValue::Struct(s) => s,
4295 _ => return None,
4296 };
4297 let mut names: Vec<String> = first.fields.keys().cloned().collect();
4298 names.sort();
4299 if names.is_empty() {
4302 return None;
4303 }
4304 for item in v {
4305 match item {
4306 RuntimeValue::Struct(s)
4307 if s.type_name == first.type_name
4308 && s.fields.len() == names.len()
4309 && names.iter().all(|n| s.fields.contains_key(n)) => {}
4310 _ => return None,
4311 }
4312 }
4313 Some((first.type_name.clone(), names))
4314}
4315
4316fn write_struct_schema(type_name: &str, field_names: &[String], out: &mut Vec<u8>) {
4326 write_str(type_name, out);
4327 write_uvarint(field_names.len() as u64, out);
4328 for f in field_names {
4329 write_str(f, out);
4330 }
4331}
4332
4333fn emit_struct_list(
4334 type_name: &str,
4335 field_names: &[String],
4336 n: usize,
4337 out: &mut Vec<u8>,
4338 encode_columns: impl FnOnce(&mut Vec<u8>) -> Result<(), String>,
4339) -> Result<(), String> {
4340 let write_schema = |out: &mut Vec<u8>| write_struct_schema(type_name, field_names, out);
4341 if let Some(id) = type_registry_id(type_name, field_names) {
4342 out.push(T_STRUCTS_TID);
4347 write_uvarint(id as u64, out);
4348 write_uvarint(n as u64, out);
4349 return encode_columns(out);
4350 }
4351 match schema_send(type_name, field_names) {
4352 SchemaEmit::Inline => {
4353 out.push(T_STRUCTS);
4354 write_schema(out);
4355 }
4356 SchemaEmit::SeqDef(id) => {
4357 out.push(T_STRUCTS_DEF);
4358 write_uvarint(id as u64, out);
4359 write_schema(out);
4360 }
4361 SchemaEmit::SeqRef(id) => {
4362 out.push(T_STRUCTS_REF);
4363 write_uvarint(id as u64, out);
4364 }
4365 SchemaEmit::CaDef => {
4366 out.push(T_STRUCTS_CDEF);
4367 write_schema(out);
4368 }
4369 SchemaEmit::CaRef(fp) => {
4370 out.push(T_STRUCTS_CREF);
4371 out.extend_from_slice(&fp.to_le_bytes());
4372 }
4373 }
4374 write_uvarint(n as u64, out);
4375 encode_columns(out)
4376}
4377
4378fn emit_structs_view(
4387 type_name: &str,
4388 field_names: &[String],
4389 n: usize,
4390 out: &mut Vec<u8>,
4391 mut get: impl FnMut(usize, usize) -> RuntimeValue,
4392) -> Result<(), String> {
4393 let f = field_names.len();
4394 out.push(T_STRUCTS_VIEW);
4395 write_str(type_name, out);
4396 write_uvarint(f as u64, out);
4397 for name in field_names {
4398 write_str(name, out);
4399 }
4400 write_uvarint(n as u64, out);
4401 let row_table_pos = out.len();
4402 out.resize(row_table_pos + n * 4, 0);
4403 let rows_start = out.len();
4404 let mut row_offsets: Vec<u32> = Vec::with_capacity(n);
4405 for r in 0..n {
4406 row_offsets.push((out.len() - rows_start) as u32);
4407 let field_table_pos = out.len();
4408 out.resize(field_table_pos + f * 4, 0);
4409 let values_start = out.len();
4410 let mut field_offsets: Vec<u32> = Vec::with_capacity(f);
4411 for fi in 0..f {
4412 field_offsets.push((out.len() - values_start) as u32);
4413 native_encode(&get(r, fi), out)?;
4414 }
4415 for (i, off) in field_offsets.iter().enumerate() {
4416 out[field_table_pos + i * 4..field_table_pos + i * 4 + 4]
4417 .copy_from_slice(&off.to_le_bytes());
4418 }
4419 }
4420 for (i, off) in row_offsets.iter().enumerate() {
4421 out[row_table_pos + i * 4..row_table_pos + i * 4 + 4].copy_from_slice(&off.to_le_bytes());
4422 }
4423 Ok(())
4424}
4425
4426fn emit_structs_view_columnar(
4431 type_name: &str,
4432 field_names: &[String],
4433 columns: &[ListRepr],
4434 out: &mut Vec<u8>,
4435) -> Result<(), String> {
4436 let f = field_names.len();
4437 let n = columns.first().map_or(0, |c| c.len());
4438 out.push(T_STRUCTS_VIEW);
4439 write_str(type_name, out);
4440 write_uvarint(f as u64, out);
4441 for name in field_names {
4442 write_str(name, out);
4443 }
4444 write_uvarint(n as u64, out);
4445 let row_table_pos = out.len();
4446 out.resize(row_table_pos + n * 4, 0);
4447 let rows_start = out.len();
4448 let mut row_offsets: Vec<u32> = Vec::with_capacity(n);
4449 let mut field_offsets: Vec<u32> = Vec::with_capacity(f);
4450 for r in 0..n {
4451 row_offsets.push((out.len() - rows_start) as u32);
4452 let field_table_pos = out.len();
4453 out.resize(field_table_pos + f * 4, 0);
4454 let values_start = out.len();
4455 field_offsets.clear();
4456 for col in columns {
4457 field_offsets.push((out.len() - values_start) as u32);
4458 write_view_cell(col, r, out)?;
4459 }
4460 for (i, off) in field_offsets.iter().enumerate() {
4461 out[field_table_pos + i * 4..field_table_pos + i * 4 + 4]
4462 .copy_from_slice(&off.to_le_bytes());
4463 }
4464 }
4465 for (i, off) in row_offsets.iter().enumerate() {
4466 out[row_table_pos + i * 4..row_table_pos + i * 4 + 4].copy_from_slice(&off.to_le_bytes());
4467 }
4468 Ok(())
4469}
4470
4471fn write_view_cell(col: &ListRepr, row: usize, out: &mut Vec<u8>) -> Result<(), String> {
4474 match col {
4475 ListRepr::Ints(v) => {
4476 out.push(T_INT);
4477 write_uvarint(zigzag(v[row]), out);
4478 }
4479 ListRepr::IntsI32(v) => {
4480 out.push(T_INT);
4481 write_uvarint(zigzag(v[row] as i64), out);
4482 }
4483 ListRepr::Floats(v) => {
4484 out.push(T_FLOAT);
4485 put_f64(out, v[row]);
4486 }
4487 ListRepr::Bools(v) => out.push(if v[row] { T_TRUE } else { T_FALSE }),
4488 ListRepr::Strings { data, ends, .. } => {
4489 let start = if row == 0 { 0 } else { ends[row - 1] as usize };
4490 let end = ends[row] as usize;
4491 let s = &data[start..end];
4492 out.push(T_TEXT);
4493 write_uvarint(s.len() as u64, out);
4494 out.extend_from_slice(s);
4495 }
4496 other => native_encode(
4497 &other
4498 .get(row)
4499 .ok_or("struct-view column row out of bounds")?,
4500 out,
4501 )?,
4502 }
4503 Ok(())
4504}
4505
4506fn emit_structs_view_fixed(
4513 type_name: &str,
4514 field_names: &[String],
4515 columns: &[ListRepr],
4516 out: &mut Vec<u8>,
4517) -> Option<()> {
4518 let kinds = columns_fview_kinds(columns)?; let f = field_names.len();
4520 let n = columns.first().map_or(0, |c| c.len());
4521 let (_, stride) = fview_layout(&kinds);
4522 out.push(T_STRUCTS_FVIEW);
4523 write_str(type_name, out);
4524 write_uvarint(f as u64, out);
4525 for name in field_names {
4526 write_str(name, out);
4527 }
4528 out.extend_from_slice(&kinds);
4529 write_uvarint(n as u64, out);
4530 out.reserve(n.saturating_mul(stride));
4531 let mut blob: Vec<u8> = Vec::new();
4532 for r in 0..n {
4533 for col in columns {
4534 match col {
4535 ListRepr::Ints(v) => out.extend_from_slice(&v[r].to_le_bytes()),
4536 ListRepr::IntsI32(v) => out.extend_from_slice(&(v[r] as i64).to_le_bytes()),
4537 ListRepr::Floats(v) => put_f64(out, v[r]),
4538 ListRepr::Bools(v) => out.push(v[r] as u8),
4539 ListRepr::Strings { data, ends, .. } => {
4540 let start = if r == 0 { 0 } else { ends[r - 1] as usize };
4541 let end = ends[r] as usize;
4542 let off = blob.len() as u32;
4543 let len = (end - start) as u32;
4544 blob.extend_from_slice(&data[start..end]);
4545 out.extend_from_slice(&off.to_le_bytes());
4546 out.extend_from_slice(&len.to_le_bytes());
4547 }
4548 _ => unreachable!("non-fixed-viewable column passed the kind check"),
4550 }
4551 }
4552 }
4553 write_uvarint(blob.len() as u64, out);
4554 out.extend_from_slice(&blob);
4555 Some(())
4556}
4557
4558fn emit_aligned_i64(v: &[i64], out: &mut Vec<u8>) {
4563 out.push(T_INTS_ALIGNED);
4564 write_uvarint(v.len() as u64, out);
4565 let after_count = out.len();
4566 let pad = (14 - after_count % 8) % 8;
4567 out.push(pad as u8);
4568 out.resize(out.len() + pad, 0);
4569 #[cfg(target_endian = "little")]
4570 {
4571 let raw = unsafe { std::slice::from_raw_parts(v.as_ptr().cast::<u8>(), v.len() * 8) };
4573 out.extend_from_slice(raw);
4574 }
4575 #[cfg(target_endian = "big")]
4576 {
4577 out.reserve(v.len() * 8);
4578 for &n in v {
4579 out.extend_from_slice(&n.to_le_bytes());
4580 }
4581 }
4582}
4583
4584fn emit_aligned_f64(v: &[f64], out: &mut Vec<u8>) {
4586 out.push(T_FLOATS_ALIGNED);
4587 write_uvarint(v.len() as u64, out);
4588 let after_count = out.len();
4589 let pad = (14 - after_count % 8) % 8;
4590 out.push(pad as u8);
4591 out.resize(out.len() + pad, 0);
4592 put_f64s(out, v);
4593}
4594
4595#[derive(Clone, Copy)]
4598pub enum WireColumn<'a> {
4599 Ints(&'a [i64]),
4601 Floats(&'a [f64]),
4603}
4604
4605pub fn build_columnar_record(
4615 from: &str,
4616 type_name: &str,
4617 fields: &[(&str, WireColumn)],
4618) -> Vec<u8> {
4619 let mut fields: Vec<(&str, WireColumn)> = fields.to_vec();
4622 fields.sort_by(|a, b| a.0.cmp(b.0));
4623 let mut out = Vec::with_capacity(from.len() + type_name.len() + 32 + fields.len() * 64);
4624 write_str(from, &mut out);
4625 out.push(T_STRUCT_VIEW);
4626 write_str(type_name, &mut out);
4627 write_uvarint(fields.len() as u64, &mut out);
4628 for (name, _) in &fields {
4629 write_str(name, &mut out);
4630 }
4631 let table_pos = out.len();
4632 out.resize(table_pos + fields.len() * 4, 0);
4633 let values_start = out.len();
4634 let mut offsets: Vec<u32> = Vec::with_capacity(fields.len());
4635 for (_, col) in fields {
4636 offsets.push((out.len() - values_start) as u32);
4637 match col {
4638 WireColumn::Ints(d) => emit_aligned_i64(d, &mut out),
4639 WireColumn::Floats(d) => emit_aligned_f64(d, &mut out),
4640 }
4641 }
4642 for (i, off) in offsets.iter().enumerate() {
4643 out[table_pos + i * 4..table_pos + i * 4 + 4].copy_from_slice(&off.to_le_bytes());
4644 }
4645 frame(
4646 WireCodec::Native,
4647 current_integrity(),
4648 WireCompression::None,
4649 out,
4650 )
4651}
4652
4653fn encode_list_repr(repr: &ListRepr, out: &mut Vec<u8>) -> Result<(), String> {
4658 let _depth = DepthGuard::enter()?;
4659 if flat_lists() || matches!(repr, ListRepr::Words32(_)) {
4666 let values = repr.to_values();
4667 out.push(T_LIST);
4668 write_uvarint(values.len() as u64, out);
4669 for x in &values {
4670 native_encode(x, out)?;
4671 }
4672 return Ok(());
4673 }
4674 match repr {
4675 ListRepr::Words32(_) => unreachable!("Words32 encodes via the flat/tagged path"),
4678 ListRepr::Ints(v) => {
4683 if struct_view_on() {
4684 emit_aligned_i64(v, out);
4685 return Ok(());
4686 }
4687 if structure() == WireStructure::Affine {
4688 if let Some((base, stride)) = detect_affine(v) {
4689 out.push(T_INTS_AFFINE);
4690 write_uvarint(zigzag(base), out);
4691 write_uvarint(zigzag(stride), out);
4692 write_uvarint(v.len() as u64, out);
4693 return Ok(());
4694 }
4695 }
4696 if structure() == WireStructure::Auto {
4697 emit_best_int_column(v, out);
4698 return Ok(());
4699 }
4700 match numerics() {
4701 WireNumerics::Varint => {
4702 out.push(T_INTS);
4703 leb128_encode(out, v.iter().copied(), v.len());
4704 }
4705 WireNumerics::Fixed => {
4706 out.push(T_INTS_FIXED);
4707 fixed_encode_i64(out, v);
4708 }
4709 WireNumerics::GroupVarint => {
4710 out.push(T_INTS_GV);
4711 gv_encode(out, v.iter().copied(), v.len());
4712 }
4713 }
4714 }
4715 ListRepr::IntsI32(v) => {
4716 if structure() == WireStructure::Auto {
4717 let widened: Vec<i64> = v.iter().map(|&n| n as i64).collect();
4718 emit_best_int_column(&widened, out);
4719 return Ok(());
4720 }
4721 match numerics() {
4722 WireNumerics::Varint => {
4723 out.push(T_INTS);
4724 leb128_encode(out, v.iter().map(|&n| n as i64), v.len());
4725 }
4726 WireNumerics::Fixed => {
4727 out.push(T_INTS_FIXED);
4728 write_uvarint(v.len() as u64, out);
4729 out.reserve(v.len() * 8);
4730 for &n in v {
4731 out.extend_from_slice(&(n as i64).to_le_bytes());
4732 }
4733 }
4734 WireNumerics::GroupVarint => {
4735 out.push(T_INTS_GV);
4736 gv_encode(out, v.iter().map(|&n| n as i64), v.len());
4737 }
4738 }
4739 }
4740 ListRepr::Floats(v) => {
4741 if struct_view_on() {
4742 emit_aligned_f64(v, out);
4743 return Ok(());
4744 }
4745 let st = structure();
4750 if matches!(st, WireStructure::Affine | WireStructure::Auto) {
4755 if let Some(bits) = detect_float_const(v) {
4756 out.push(T_FLOATS_CONST);
4757 out.extend_from_slice(&bits.to_le_bytes());
4758 write_uvarint(v.len() as u64, out);
4759 return Ok(());
4760 }
4761 if let Some((base, stride)) = detect_float_affine(v) {
4762 out.push(T_FLOATS_AFFINE);
4763 put_f64(out, base);
4764 put_f64(out, stride);
4765 write_uvarint(v.len() as u64, out);
4766 return Ok(());
4767 }
4768 }
4769 let sparse: Option<Vec<u8>> = if st == WireStructure::Auto {
4776 detect_float_sparse(v).map(|(dom, exc)| {
4777 let mut c = vec![T_FLOATS_SPARSE];
4778 c.extend_from_slice(&dom.to_le_bytes());
4779 write_uvarint(v.len() as u64, &mut c);
4780 write_uvarint(exc.len() as u64, &mut c);
4781 let mut prev = 0usize;
4782 for (i, bits) in &exc {
4783 write_uvarint((i - prev) as u64, &mut c);
4784 prev = *i;
4785 c.extend_from_slice(&bits.to_le_bytes());
4786 }
4787 c
4788 })
4789 } else {
4790 None
4791 };
4792 let xor: Option<Vec<u8>> = if floats_mode() == WireFloats::XorDelta {
4793 let mut body = Vec::with_capacity(v.len() + 2);
4794 floats_xor_encode(&mut body, v);
4795 if body.len() < floats_memcpy_body_len(v.len()) {
4796 let mut c = vec![T_FLOATS_XOR];
4797 c.extend_from_slice(&body);
4798 Some(c)
4799 } else {
4800 None
4801 }
4802 } else {
4803 None
4804 };
4805 let geometric: Option<Vec<u8>> = if st == WireStructure::Auto {
4806 detect_float_geometric(v).map(|(base, ratio)| {
4807 let mut c = vec![T_FLOATS_GEOMETRIC];
4808 put_f64(&mut c, base);
4809 put_f64(&mut c, ratio);
4810 write_uvarint(v.len() as u64, &mut c);
4811 c
4812 })
4813 } else {
4814 None
4815 };
4816 let periodic: Option<Vec<u8>> = if st == WireStructure::Auto {
4817 detect_float_period(v).map(|p| {
4818 let mut c = vec![T_FLOATS_PERIODIC];
4819 write_uvarint(p as u64, &mut c);
4820 write_uvarint(v.len() as u64, &mut c);
4821 put_f64s(&mut c, &v[..p]);
4822 c
4823 })
4824 } else {
4825 None
4826 };
4827 if let Some(c) = [sparse, xor, geometric, periodic]
4828 .into_iter()
4829 .flatten()
4830 .min_by_key(Vec::len)
4831 {
4832 if c.len() < floats_memcpy_body_len(v.len()) + 1 {
4834 out.extend_from_slice(&c);
4835 return Ok(());
4836 }
4837 }
4838 out.push(T_FLOATS);
4839 write_uvarint(v.len() as u64, out);
4840 put_f64s(out, v);
4842 }
4843 ListRepr::Bools(v) => {
4844 if structure() == WireStructure::Auto {
4847 emit_best_bool_column(v, out);
4848 } else {
4849 bool_bitpack(v, out);
4850 }
4851 }
4852 ListRepr::Strings { data, ends, .. } => {
4853 if structure() == WireStructure::Auto {
4856 emit_best_string_column(data, ends, out);
4857 } else {
4858 write_string_array_from_ends(out, data, ends);
4859 }
4860 }
4861 ListRepr::Structs {
4864 type_name,
4865 field_names,
4866 columns,
4867 } => {
4868 let n = columns.first().map_or(0, |c| c.len());
4869 if struct_view_on() {
4870 if numerics() == WireNumerics::Fixed
4877 && emit_structs_view_fixed(type_name, field_names, columns, out).is_some()
4878 {
4879 return Ok(());
4880 }
4881 return emit_structs_view_columnar(type_name, field_names, columns, out);
4882 }
4883 emit_struct_list(type_name, field_names, n, out, |out| {
4884 for col in columns {
4885 encode_list_repr(col, out)?;
4886 }
4887 Ok(())
4888 })?;
4889 }
4890 ListRepr::Inductives {
4895 inductive_type,
4896 ctor_dict,
4897 ctors,
4898 ranks: _,
4899 arg_cols,
4900 } => {
4901 out.push(T_INDUCTIVES);
4902 write_str(inductive_type, out);
4903 write_uvarint(ctor_dict.len() as u64, out);
4904 for (c, name) in ctor_dict.iter().enumerate() {
4905 write_str(name, out);
4906 write_uvarint(arg_cols[c].len() as u64, out); }
4908 let idx: Vec<i64> = ctors.iter().map(|&c| c as i64).collect();
4909 encode_list_repr(&ListRepr::Ints(idx), out)?;
4910 for cols in arg_cols {
4911 for col in cols {
4912 encode_list_repr(col, out)?;
4913 }
4914 }
4915 }
4916 ListRepr::WireStructs { .. } | ListRepr::WireColumn { .. } => {
4919 let materialized = ListRepr::from_values(repr.to_values());
4920 return encode_list_repr(&materialized, out);
4921 }
4922 ListRepr::Boxed(v) => {
4923 if !v.is_empty() && v.iter().all(|x| matches!(x, RuntimeValue::Text(_))) {
4924 let mut sdata = Vec::new();
4929 let mut sends = Vec::with_capacity(v.len());
4930 for x in v {
4931 if let RuntimeValue::Text(s) = x {
4932 sdata.extend_from_slice(s.as_bytes());
4933 sends.push(sdata.len() as u32);
4934 }
4935 }
4936 if structure() == WireStructure::Auto {
4937 emit_best_string_column(&sdata, &sends, out);
4938 } else {
4939 write_string_array_from_ends(out, &sdata, &sends);
4940 }
4941 } else if let Some((type_name, field_names)) = struct_schema(v) {
4942 if struct_view_on() {
4943 return emit_structs_view(&type_name, &field_names, v.len(), out, |row, fi| {
4946 match &v[row] {
4947 RuntimeValue::Struct(sv) => {
4948 sv.fields.get(&field_names[fi]).cloned().unwrap()
4949 }
4950 _ => unreachable!("struct_schema guaranteed all-struct"),
4951 }
4952 });
4953 }
4954 emit_struct_list(&type_name, &field_names, v.len(), out, |out| {
4957 for fname in &field_names {
4958 let column: Vec<RuntimeValue> = v
4959 .iter()
4960 .map(|s| match s {
4961 RuntimeValue::Struct(sv) => sv.fields.get(fname).cloned().unwrap(),
4962 _ => unreachable!("struct_schema guaranteed all-struct"),
4963 })
4964 .collect();
4965 encode_list_repr(&ListRepr::from_values(column), out)?;
4966 }
4967 Ok(())
4968 })?;
4969 } else if let Some(ind) = ListRepr::build_inductives(v) {
4970 encode_list_repr(&ind, out)?;
4973 } else {
4974 out.push(T_LIST);
4976 write_uvarint(v.len() as u64, out);
4977 for x in v {
4978 native_encode(x, out)?;
4979 }
4980 }
4981 }
4982 }
4983 Ok(())
4984}
4985
4986#[inline(never)]
4989fn encode_money(m: &logicaffeine_base::Money, out: &mut Vec<u8>) {
4990 out.push(T_MONEY);
4991 let (negative, magnitude, scale) = m.amount.to_le_bytes();
4992 out.push(negative as u8);
4993 write_uvarint(magnitude.len() as u64, out);
4994 out.extend_from_slice(&magnitude);
4995 write_uvarint(scale as u64, out);
4996 let code = m.currency.code.as_bytes();
4997 write_uvarint(code.len() as u64, out);
4998 out.extend_from_slice(code);
4999}
5000
5001#[inline(never)]
5004fn decode_money(buf: &[u8], pos: &mut usize) -> Option<RuntimeValue> {
5005 let negative = *buf.get(*pos)? != 0;
5006 *pos += 1;
5007 let len = read_uvarint(buf, pos)? as usize;
5008 let bytes = buf.get(*pos..pos.checked_add(len)?)?;
5009 *pos += len;
5010 let scale = u32::try_from(read_uvarint(buf, pos)?).ok()?;
5011 let amount = logicaffeine_base::Decimal::from_le_bytes(negative, bytes, scale);
5012 let clen = read_uvarint(buf, pos)? as usize;
5013 let cbytes = buf.get(*pos..pos.checked_add(clen)?)?;
5014 *pos += clen;
5015 let code = std::str::from_utf8(cbytes).ok()?;
5016 let currency =
5017 logicaffeine_base::money::currency::by_code(code).unwrap_or(logicaffeine_base::Currency {
5018 code: "XXX",
5019 scale: 0,
5020 });
5021 Some(RuntimeValue::Money(Rc::new(logicaffeine_base::Money {
5022 amount,
5023 currency,
5024 })))
5025}
5026
5027fn encode_uuid(u: &logicaffeine_base::Uuid, out: &mut Vec<u8>) {
5029 out.push(T_UUID);
5030 out.extend_from_slice(u.as_bytes());
5031}
5032
5033fn decode_uuid(buf: &[u8], pos: &mut usize) -> Option<RuntimeValue> {
5035 let bytes = buf.get(*pos..pos.checked_add(16)?)?;
5036 *pos += 16;
5037 let mut arr = [0u8; 16];
5038 arr.copy_from_slice(bytes);
5039 Some(RuntimeValue::Uuid(Rc::new(
5040 logicaffeine_base::Uuid::from_bytes(arr),
5041 )))
5042}
5043
5044fn never_sent() -> String {
5048 format!(
5049 "{} stays with its program and is never sent",
5050 logicaffeine_base::exact_real::STAYS_WITH_ITS_PROGRAM
5051 )
5052}
5053
5054fn native_encode(v: &RuntimeValue, out: &mut Vec<u8>) -> Result<(), String> {
5055 let _depth = DepthGuard::enter()?;
5056 if dedup_encode_prefix(v, out) {
5060 return Ok(());
5061 }
5062 match v {
5063 RuntimeValue::Nothing => out.push(T_NOTHING),
5064 RuntimeValue::Bool(false) => out.push(T_FALSE),
5065 RuntimeValue::Bool(true) => out.push(T_TRUE),
5066 RuntimeValue::Int(n) => {
5067 out.push(T_INT);
5068 write_uvarint(zigzag(*n), out);
5069 }
5070 RuntimeValue::Word(w) => {
5071 out.push(T_WORD);
5072 out.push(w.width() as u8);
5073 write_uvarint(w.to_u64(), out);
5074 }
5075 RuntimeValue::Lanes(_) => {
5076 return Err(
5077 "a SIMD lane vector is a transient compute value, not a wire type".to_string(),
5078 );
5079 }
5080 RuntimeValue::ComplexF(c) => {
5081 out.push(T_COMPLEXF);
5082 put_f64(out, c.re());
5083 put_f64(out, c.im());
5084 }
5085 RuntimeValue::BigInt(b) => {
5088 out.push(T_BIGINT);
5089 let (negative, magnitude) = b.to_le_bytes();
5090 out.push(negative as u8);
5091 write_uvarint(magnitude.len() as u64, out);
5092 out.extend_from_slice(&magnitude);
5093 }
5094 RuntimeValue::Rational(r) => {
5097 out.push(T_RATIONAL);
5098 let (num_negative, num_magnitude) = r.numerator().to_le_bytes();
5099 out.push(num_negative as u8);
5100 write_uvarint(num_magnitude.len() as u64, out);
5101 out.extend_from_slice(&num_magnitude);
5102 let (_den_sign, den_magnitude) = r.denominator().to_le_bytes();
5103 write_uvarint(den_magnitude.len() as u64, out);
5104 out.extend_from_slice(&den_magnitude);
5105 }
5106 RuntimeValue::Decimal(d) => {
5109 out.push(T_DECIMAL);
5110 let (negative, magnitude, scale) = d.to_le_bytes();
5111 out.push(negative as u8);
5112 write_uvarint(magnitude.len() as u64, out);
5113 out.extend_from_slice(&magnitude);
5114 write_uvarint(scale as u64, out);
5115 }
5116 RuntimeValue::Money(m) => encode_money(m, out),
5120 RuntimeValue::Uuid(u) => encode_uuid(u, out),
5121 RuntimeValue::Complex(c) => {
5124 out.push(T_COMPLEX);
5125 for part in [c.re(), c.im()] {
5126 let (neg, num) = part.numerator().to_le_bytes();
5127 out.push(neg as u8);
5128 write_uvarint(num.len() as u64, out);
5129 out.extend_from_slice(&num);
5130 let (_den_sign, den) = part.denominator().to_le_bytes();
5131 write_uvarint(den.len() as u64, out);
5132 out.extend_from_slice(&den);
5133 }
5134 }
5135 RuntimeValue::Modular(m) => {
5137 out.push(T_MODULAR);
5138 let (_, value) = m.value().to_le_bytes();
5139 write_uvarint(value.len() as u64, out);
5140 out.extend_from_slice(&value);
5141 let (_, modulus) = m.modulus().to_le_bytes();
5142 write_uvarint(modulus.len() as u64, out);
5143 out.extend_from_slice(&modulus);
5144 }
5145 RuntimeValue::Float(f) => {
5146 out.push(T_FLOAT);
5147 put_f64(out, *f);
5148 }
5149 RuntimeValue::Char(c) => {
5150 out.push(T_CHAR);
5151 write_uvarint(*c as u64, out);
5152 }
5153 RuntimeValue::Text(s) => {
5154 out.push(T_TEXT);
5155 write_str(s, out);
5156 }
5157 RuntimeValue::Duration(n) => {
5158 out.push(T_DURATION);
5159 write_uvarint(zigzag(*n), out);
5160 }
5161 RuntimeValue::Date(n) => {
5162 out.push(T_DATE);
5163 write_uvarint(zigzag(*n as i64), out);
5164 }
5165 RuntimeValue::Moment(n) => {
5166 out.push(T_MOMENT);
5167 write_uvarint(zigzag(*n), out);
5168 }
5169 RuntimeValue::Span { months, days } => {
5170 out.push(T_SPAN);
5171 write_uvarint(zigzag(*months as i64), out);
5172 write_uvarint(zigzag(*days as i64), out);
5173 }
5174 RuntimeValue::Time(n) => {
5175 out.push(T_TIME);
5176 write_uvarint(zigzag(*n), out);
5177 }
5178 RuntimeValue::Peer(topic) => {
5179 out.push(T_PEER);
5180 write_str(topic, out);
5181 }
5182 RuntimeValue::List(items) => encode_list_repr(&items.borrow(), out)?,
5183 RuntimeValue::Tuple(items) => {
5184 out.push(T_TUPLE);
5185 write_uvarint(items.len() as u64, out);
5186 for x in items.iter() {
5187 native_encode(x, out)?;
5188 }
5189 }
5190 RuntimeValue::Set(items) => {
5191 let b = items.borrow();
5192 if !b.is_empty() && b.iter().all(|x| matches!(x, RuntimeValue::Int(_))) {
5193 let mut ints: Vec<i64> = b
5198 .iter()
5199 .map(|x| {
5200 if let RuntimeValue::Int(n) = x {
5201 *n
5202 } else {
5203 unreachable!()
5204 }
5205 })
5206 .collect();
5207 ints.sort_unstable();
5208 ints.dedup();
5209 out.push(T_SET_INTS);
5210 emit_best_int_column(&ints, out);
5211 } else if !b.is_empty() && b.iter().all(|x| matches!(x, RuntimeValue::Text(_))) {
5212 let mut strs: Vec<String> = b
5217 .iter()
5218 .map(|x| {
5219 if let RuntimeValue::Text(t) = x {
5220 (**t).clone()
5221 } else {
5222 unreachable!()
5223 }
5224 })
5225 .collect();
5226 strs.sort_unstable();
5227 strs.dedup();
5228 out.push(T_SET_STRINGS);
5229 write_uvarint(strs.len() as u64, out);
5230 let mut prev: &str = "";
5231 for s in &strs {
5232 let common: usize = s
5234 .chars()
5235 .zip(prev.chars())
5236 .take_while(|(a, b)| a == b)
5237 .map(|(a, _)| a.len_utf8())
5238 .sum();
5239 write_uvarint(common as u64, out);
5240 write_str(&s[common..], out);
5241 prev = s;
5242 }
5243 } else {
5244 out.push(T_SET);
5250 let mut encoded: Vec<Vec<u8>> = Vec::with_capacity(b.len());
5251 for x in b.iter() {
5252 let mut xb = Vec::new();
5253 native_encode(x, &mut xb)?;
5254 encoded.push(xb);
5255 }
5256 encoded.sort_unstable();
5257 write_uvarint(encoded.len() as u64, out);
5258 for xb in &encoded {
5259 out.extend_from_slice(xb);
5260 }
5261 }
5262 }
5263 RuntimeValue::Map(m) => {
5264 let b = m.borrow();
5265 if !b.is_empty() && b.keys().all(|k| matches!(k, RuntimeValue::Int(_))) {
5266 let mut pairs: Vec<(i64, RuntimeValue)> = b
5272 .iter()
5273 .map(|(k, v)| match k {
5274 RuntimeValue::Int(n) => (*n, v.clone()),
5275 _ => unreachable!("all keys verified Int"),
5276 })
5277 .collect();
5278 pairs.sort_by_key(|(k, _)| *k);
5279 let keys: Vec<i64> = pairs.iter().map(|(k, _)| *k).collect();
5280 let vals: Vec<RuntimeValue> = pairs.into_iter().map(|(_, v)| v).collect();
5281 out.push(T_MAP_INTKEY);
5282 emit_best_int_column(&keys, out);
5283 if vals.iter().all(|v| matches!(v, RuntimeValue::Int(_))) {
5288 out.push(1u8);
5289 let int_vals: Vec<i64> = vals
5290 .iter()
5291 .map(|v| match v {
5292 RuntimeValue::Int(n) => *n,
5293 _ => unreachable!("all values verified Int"),
5294 })
5295 .collect();
5296 emit_best_int_column(&int_vals, out);
5297 } else if vals.iter().all(|v| matches!(v, RuntimeValue::Text(_))) {
5298 out.push(2u8);
5304 write_uvarint(vals.len() as u64, out);
5305 let mut prev: &str = "";
5306 for v in &vals {
5307 let s = match v {
5308 RuntimeValue::Text(t) => t.as_str(),
5309 _ => unreachable!("all values verified Text"),
5310 };
5311 let common: usize = s
5312 .chars()
5313 .zip(prev.chars())
5314 .take_while(|(a, b)| a == b)
5315 .map(|(a, _)| a.len_utf8())
5316 .sum();
5317 write_uvarint(common as u64, out);
5318 write_str(&s[common..], out);
5319 prev = s;
5320 }
5321 } else if vals.iter().all(|v| matches!(v, RuntimeValue::Struct(_))) {
5322 out.push(3u8);
5328 let vlist = RuntimeValue::List(Rc::new(RefCell::new(ListRepr::from_values(
5329 vals.clone(),
5330 ))));
5331 native_encode(&vlist, out)?;
5332 } else {
5333 out.push(0u8);
5334 write_uvarint(vals.len() as u64, out);
5335 for v in &vals {
5336 native_encode(v, out)?;
5337 }
5338 }
5339 } else {
5340 out.push(T_MAP);
5341 let mut entries: Vec<(Vec<u8>, Vec<u8>)> = Vec::with_capacity(b.len());
5343 for (k, val) in b.iter() {
5344 let mut kb = Vec::new();
5345 native_encode(k, &mut kb)?;
5346 let mut vb = Vec::new();
5347 native_encode(val, &mut vb)?;
5348 entries.push((kb, vb));
5349 }
5350 entries.sort_by(|a, b| a.0.cmp(&b.0));
5351 write_uvarint(entries.len() as u64, out);
5352 for (kb, vb) in entries {
5353 out.extend_from_slice(&kb);
5354 out.extend_from_slice(&vb);
5355 }
5356 }
5357 }
5358 RuntimeValue::Struct(s) => {
5359 let mut fields: Vec<(&String, &RuntimeValue)> = s.fields.iter().collect();
5365 fields.sort_by(|a, b| a.0.cmp(b.0));
5366 let field_names: Vec<String> = fields.iter().map(|(n, _)| (*n).clone()).collect();
5367 if struct_view_on() {
5368 out.push(T_STRUCT_VIEW);
5372 write_str(&s.type_name, out);
5373 write_uvarint(fields.len() as u64, out);
5374 for (name, _) in &fields {
5375 write_str(name, out);
5376 }
5377 let table_pos = out.len();
5378 out.resize(table_pos + fields.len() * 4, 0);
5379 let values_start = out.len();
5380 let mut offsets: Vec<u32> = Vec::with_capacity(fields.len());
5381 for (_, val) in &fields {
5382 offsets.push((out.len() - values_start) as u32);
5383 native_encode(val, out)?;
5384 }
5385 for (i, off) in offsets.iter().enumerate() {
5386 out[table_pos + i * 4..table_pos + i * 4 + 4]
5387 .copy_from_slice(&off.to_le_bytes());
5388 }
5389 } else if let Some(id) = type_registry_id(&s.type_name, &field_names) {
5390 out.push(T_STRUCT_TID);
5394 write_uvarint(id as u64, out);
5395 for (_, val) in &fields {
5396 native_encode(val, out)?;
5397 }
5398 } else {
5399 match schema_send(&s.type_name, &field_names) {
5400 SchemaEmit::Inline => {
5401 out.push(T_STRUCT);
5402 write_str(&s.type_name, out);
5403 write_uvarint(fields.len() as u64, out);
5404 for (name, val) in &fields {
5405 write_str(name, out);
5406 native_encode(val, out)?;
5407 }
5408 }
5409 SchemaEmit::SeqDef(id) => {
5410 out.push(T_STRUCT_DEF);
5411 write_uvarint(id as u64, out);
5412 write_struct_schema(&s.type_name, &field_names, out);
5413 for (_, val) in &fields {
5414 native_encode(val, out)?;
5415 }
5416 }
5417 SchemaEmit::SeqRef(id) => {
5418 out.push(T_STRUCT_REF);
5419 write_uvarint(id as u64, out);
5420 for (_, val) in &fields {
5421 native_encode(val, out)?;
5422 }
5423 }
5424 SchemaEmit::CaDef => {
5425 out.push(T_STRUCT_CDEF);
5426 write_struct_schema(&s.type_name, &field_names, out);
5427 for (_, val) in &fields {
5428 native_encode(val, out)?;
5429 }
5430 }
5431 SchemaEmit::CaRef(fp) => {
5432 out.push(T_STRUCT_CREF);
5433 out.extend_from_slice(&fp.to_le_bytes());
5434 for (_, val) in &fields {
5435 native_encode(val, out)?;
5436 }
5437 }
5438 }
5439 }
5440 }
5441 RuntimeValue::Inductive(ind) => {
5442 if let Some((enum_id, ctor_idx)) =
5443 type_registry_enum_id(&ind.inductive_type, &ind.constructor)
5444 {
5445 out.push(T_INDUCTIVE_TID);
5448 write_uvarint(enum_id as u64, out);
5449 write_uvarint(ctor_idx as u64, out);
5450 write_uvarint(ind.args.len() as u64, out);
5451 for a in &ind.args {
5452 native_encode(a, out)?;
5453 }
5454 } else {
5455 out.push(T_INDUCTIVE);
5456 write_str(&ind.inductive_type, out);
5457 write_str(&ind.constructor, out);
5458 write_uvarint(ind.args.len() as u64, out);
5459 for a in &ind.args {
5460 native_encode(a, out)?;
5461 }
5462 }
5463 }
5464 RuntimeValue::Chan(_) | RuntimeValue::TaskHandle(_) => {
5465 return Err("a channel or task handle cannot be sent over the network".to_string());
5466 }
5467 RuntimeValue::Crdt(_) => {
5468 return Err("a CRDT value is shared via Merge/Sync, not sent inline".to_string());
5469 }
5470 RuntimeValue::Algebraic(_) | RuntimeValue::ExactReal(_) | RuntimeValue::Ordinal(_) => {
5471 let Some((kind, bytes)) = crate::semantics::exact::exact_bytes(v) else {
5472 return Err(never_sent());
5473 };
5474 out.push(T_EXACT);
5475 out.push(kind);
5476 write_uvarint(bytes.len() as u64, out);
5477 out.extend_from_slice(&bytes);
5478 }
5479 RuntimeValue::Hyperreal(_) | RuntimeValue::Hypernatural(_) => {
5480 let Some((kind, name, residues, bytes)) = crate::semantics::exact::scaled_bytes(v) else {
5481 return Err(never_sent());
5482 };
5483 out.push(T_SCALED);
5484 out.push(kind);
5485 write_str(&name, out);
5486 write_uvarint(residues.len() as u64, out);
5487 out.extend_from_slice(&residues);
5488 write_uvarint(bytes.len() as u64, out);
5489 out.extend_from_slice(&bytes);
5490 }
5491 RuntimeValue::Depends(d) => {
5492 let (name, residues) = crate::semantics::exact::scale_parts(&d.scale);
5493 out.push(T_DEPENDS);
5494 write_str(&name, out);
5495 write_uvarint(residues.len() as u64, out);
5496 out.extend_from_slice(&residues);
5497 write_uvarint(d.value.modulus(), out);
5498 for branch in d.value.raw_branches() {
5499 match branch {
5500 None => out.push(0),
5501 Some(b) => {
5502 out.push(1);
5503 native_encode(&b.0, out)?;
5504 }
5505 }
5506 }
5507 }
5508 RuntimeValue::Converging(c) => {
5509 out.push(T_CONVERGING);
5510 native_encode(c.value(), out)?;
5511 write_uvarint(c.steps(), out);
5512 write_uvarint(c.revisions(), out);
5513 match c.certificate() {
5514 None => out.push(0),
5515 Some(cert) => {
5516 out.push(1);
5517 write_str(cert, out);
5518 }
5519 }
5520 }
5521 RuntimeValue::View(_) | RuntimeValue::Action(_) => {
5523 return Err(
5524 "a view or callback belongs to the page that made it and cannot be sent"
5525 .to_string(),
5526 );
5527 }
5528 RuntimeValue::Function(f) => {
5529 match &f.generated {
5533 Some(expr) => {
5534 out.push(T_FUNC);
5535 write_uvarint(f.param_names.len() as u64, out);
5536 serialize_gen(expr, out);
5537 }
5538 None => return Err("a Function cannot be sent over the network".to_string()),
5539 }
5540 }
5541 RuntimeValue::Quantity(qv) => {
5544 out.push(T_QUANTITY);
5545 let (num_negative, num_magnitude) = qv.q.magnitude_si().numerator().to_le_bytes();
5546 out.push(num_negative as u8);
5547 write_uvarint(num_magnitude.len() as u64, out);
5548 out.extend_from_slice(&num_magnitude);
5549 let (_den_sign, den_magnitude) = qv.q.magnitude_si().denominator().to_le_bytes();
5550 write_uvarint(den_magnitude.len() as u64, out);
5551 out.extend_from_slice(&den_magnitude);
5552 let dim = qv.q.dimension();
5553 for d in logicaffeine_base::BaseDim::ALL {
5554 let e = dim.exponent(d);
5555 write_uvarint(zigzag(e.numerator() as i64), out);
5556 write_uvarint(zigzag(e.denominator() as i64), out);
5557 }
5558 let sym = qv.unit.symbol.as_bytes();
5559 write_uvarint(sym.len() as u64, out);
5560 out.extend_from_slice(sym);
5561 }
5562 }
5563 Ok(())
5564}
5565
5566const PREALLOC_CAP: usize = 4096;
5569
5570fn bounded_count(n: u64) -> Option<usize> {
5576 let n = n as usize;
5577 (n <= receive_limits().max_elements).then_some(n)
5578}
5579
5580fn native_decode(buf: &[u8], pos: &mut usize) -> Option<RuntimeValue> {
5581 let _depth = DecodeDepthGuard::enter()?;
5584 let tag = *buf.get(*pos)?;
5585 *pos += 1;
5586 if tag == T_SHARED_REF {
5589 let id = read_uvarint(buf, pos)?;
5590 return DECODE_MEMO.with(|c| c.borrow().get(&id).cloned());
5591 }
5592 if tag == T_SHARED_DEF {
5593 let id = read_uvarint(buf, pos)?;
5594 let v = native_decode(buf, pos)?;
5595 DECODE_MEMO.with(|c| c.borrow_mut().insert(id, v.clone()));
5596 return Some(v);
5597 }
5598 Some(match tag {
5599 T_NOTHING => RuntimeValue::Nothing,
5600 T_FALSE => RuntimeValue::Bool(false),
5601 T_TRUE => RuntimeValue::Bool(true),
5602 T_INT => RuntimeValue::Int(unzigzag(read_uvarint(buf, pos)?)),
5603 T_WORD => {
5604 let width = *buf.get(*pos)? as u32;
5605 *pos += 1;
5606 let bits = read_uvarint(buf, pos)?;
5607 RuntimeValue::Word(logicaffeine_base::WordVal::from_u64(width, bits)?)
5608 }
5609 T_BIGINT => {
5610 let negative = *buf.get(*pos)? != 0;
5611 *pos += 1;
5612 let len = read_uvarint(buf, pos)? as usize;
5613 let bytes = buf.get(*pos..pos.checked_add(len)?)?;
5614 *pos += len;
5615 RuntimeValue::from_bigint(logicaffeine_base::BigInt::from_le_bytes(negative, bytes))
5616 }
5617 T_RATIONAL => {
5618 let num_negative = *buf.get(*pos)? != 0;
5619 *pos += 1;
5620 let num_len = read_uvarint(buf, pos)? as usize;
5621 let num_bytes = buf.get(*pos..pos.checked_add(num_len)?)?;
5622 *pos += num_len;
5623 let num = logicaffeine_base::BigInt::from_le_bytes(num_negative, num_bytes);
5624 let den_len = read_uvarint(buf, pos)? as usize;
5625 let den_bytes = buf.get(*pos..pos.checked_add(den_len)?)?;
5626 *pos += den_len;
5627 let den = logicaffeine_base::BigInt::from_le_bytes(false, den_bytes);
5628 RuntimeValue::from_rational(logicaffeine_base::Rational::new(num, den)?)
5630 }
5631 T_DECIMAL => {
5632 let negative = *buf.get(*pos)? != 0;
5633 *pos += 1;
5634 let len = read_uvarint(buf, pos)? as usize;
5635 let bytes = buf.get(*pos..pos.checked_add(len)?)?;
5636 *pos += len;
5637 let scale = u32::try_from(read_uvarint(buf, pos)?).ok()?;
5638 RuntimeValue::Decimal(Rc::new(logicaffeine_base::Decimal::from_le_bytes(
5641 negative, bytes, scale,
5642 )))
5643 }
5644 T_MONEY => decode_money(buf, pos)?,
5646 T_UUID => decode_uuid(buf, pos)?,
5647 T_EXACT => {
5648 let kind = *buf.get(*pos)?;
5649 *pos += 1;
5650 let n = read_uvarint(buf, pos)? as usize;
5651 let bytes = buf.get(*pos..pos.checked_add(n)?)?;
5652 *pos += n;
5653 crate::semantics::exact::from_exact_bytes(kind, bytes)?
5654 }
5655 T_SCALED => {
5656 let kind = *buf.get(*pos)?;
5657 *pos += 1;
5658 let name = read_str(buf, pos)?;
5659 let rn = read_uvarint(buf, pos)? as usize;
5660 let residues = buf.get(*pos..pos.checked_add(rn)?)?.to_vec();
5661 *pos += rn;
5662 let n = read_uvarint(buf, pos)? as usize;
5663 let bytes = buf.get(*pos..pos.checked_add(n)?)?;
5664 *pos += n;
5665 crate::semantics::exact::from_scaled_bytes(kind, &name, &residues, bytes)?
5666 }
5667 T_DEPENDS => {
5668 let name = read_str(buf, pos)?;
5669 let rn = read_uvarint(buf, pos)? as usize;
5670 let residues = buf.get(*pos..pos.checked_add(rn)?)?.to_vec();
5671 *pos += rn;
5672 let modulus = read_uvarint(buf, pos)?;
5673 if modulus == 0 || modulus > logicaffeine_base::exact_codec::MAX_WIRE_LEN as u64 {
5674 return None;
5675 }
5676 let mut branches = Vec::with_capacity(modulus as usize);
5677 for _ in 0..modulus {
5678 branches.push(match *buf.get(*pos)? {
5679 0 => {
5680 *pos += 1;
5681 None
5682 }
5683 1 => {
5684 *pos += 1;
5685 Some(native_decode(buf, pos)?)
5686 }
5687 _ => return None,
5688 });
5689 }
5690 crate::semantics::exact::depends_from_parts(&name, &residues, modulus, branches)?
5691 }
5692 T_CONVERGING => {
5693 let value = native_decode(buf, pos)?;
5694 if matches!(value, RuntimeValue::Converging(_)) {
5695 return None;
5696 }
5697 let steps = read_uvarint(buf, pos)?;
5698 let revisions = read_uvarint(buf, pos)?;
5699 let converging = match *buf.get(*pos)? {
5700 0 => {
5701 *pos += 1;
5702 logicaffeine_base::limit_value::Converging::provisional(value, steps, revisions)
5703 }
5704 1 => {
5705 *pos += 1;
5706 if steps != 0 || revisions != 0 {
5707 return None;
5708 }
5709 let cert = read_str(buf, pos)?;
5710 logicaffeine_base::limit_value::Converging::settled(value, &cert)
5711 }
5712 _ => return None,
5713 };
5714 RuntimeValue::Converging(Rc::new(converging))
5715 }
5716 T_COMPLEX => {
5717 let re_neg = *buf.get(*pos)? != 0;
5719 *pos += 1;
5720 let re_nlen = read_uvarint(buf, pos)? as usize;
5721 let re_nb = buf.get(*pos..pos.checked_add(re_nlen)?)?;
5722 *pos += re_nlen;
5723 let re_num = logicaffeine_base::BigInt::from_le_bytes(re_neg, re_nb);
5724 let re_dlen = read_uvarint(buf, pos)? as usize;
5725 let re_db = buf.get(*pos..pos.checked_add(re_dlen)?)?;
5726 *pos += re_dlen;
5727 let re = logicaffeine_base::Rational::new(
5728 re_num,
5729 logicaffeine_base::BigInt::from_le_bytes(false, re_db),
5730 )?;
5731 let im_neg = *buf.get(*pos)? != 0;
5732 *pos += 1;
5733 let im_nlen = read_uvarint(buf, pos)? as usize;
5734 let im_nb = buf.get(*pos..pos.checked_add(im_nlen)?)?;
5735 *pos += im_nlen;
5736 let im_num = logicaffeine_base::BigInt::from_le_bytes(im_neg, im_nb);
5737 let im_dlen = read_uvarint(buf, pos)? as usize;
5738 let im_db = buf.get(*pos..pos.checked_add(im_dlen)?)?;
5739 *pos += im_dlen;
5740 let im = logicaffeine_base::Rational::new(
5741 im_num,
5742 logicaffeine_base::BigInt::from_le_bytes(false, im_db),
5743 )?;
5744 RuntimeValue::Complex(Rc::new(logicaffeine_base::Complex::new(re, im)))
5745 }
5746 T_MODULAR => {
5747 let vlen = read_uvarint(buf, pos)? as usize;
5748 let vb = buf.get(*pos..pos.checked_add(vlen)?)?;
5749 *pos += vlen;
5750 let v = logicaffeine_base::BigInt::from_le_bytes(false, vb);
5751 let nlen = read_uvarint(buf, pos)? as usize;
5752 let nb = buf.get(*pos..pos.checked_add(nlen)?)?;
5753 *pos += nlen;
5754 let n = logicaffeine_base::BigInt::from_le_bytes(false, nb);
5755 RuntimeValue::Modular(Rc::new(logicaffeine_base::Modular::new(v, n)?))
5756 }
5757 T_QUANTITY => {
5758 let num_neg = *buf.get(*pos)? != 0;
5760 *pos += 1;
5761 let nlen = read_uvarint(buf, pos)? as usize;
5762 let nb = buf.get(*pos..pos.checked_add(nlen)?)?;
5763 *pos += nlen;
5764 let num = logicaffeine_base::BigInt::from_le_bytes(num_neg, nb);
5765 let dlen = read_uvarint(buf, pos)? as usize;
5766 let db = buf.get(*pos..pos.checked_add(dlen)?)?;
5767 *pos += dlen;
5768 let magnitude = logicaffeine_base::Rational::new(
5769 num,
5770 logicaffeine_base::BigInt::from_le_bytes(false, db),
5771 )?;
5772 let mut exps = [logicaffeine_base::Exp::ZERO; logicaffeine_base::BaseDim::COUNT];
5774 for slot in exps.iter_mut() {
5775 let en = unzigzag(read_uvarint(buf, pos)?) as i32;
5776 let ed = unzigzag(read_uvarint(buf, pos)?) as i32;
5777 *slot = logicaffeine_base::Exp::new(en, if ed == 0 { 1 } else { ed });
5778 }
5779 let dim = logicaffeine_base::Dimension::from_exps(exps);
5780 let sym = read_str(buf, pos)?;
5782 let unit = logicaffeine_base::quantity::units::by_name(&sym)
5783 .filter(|u| u.dimension == dim)
5784 .unwrap_or_else(|| {
5785 logicaffeine_base::Unit::linear("", dim, logicaffeine_base::Rational::one())
5786 });
5787 RuntimeValue::Quantity(Rc::new(crate::interpreter::QuantityValue {
5788 q: logicaffeine_base::Quantity::si(magnitude, dim),
5789 unit,
5790 }))
5791 }
5792 T_FLOAT => {
5793 let b: [u8; 8] = buf.get(*pos..pos.checked_add(8)?)?.try_into().ok()?;
5794 *pos += 8;
5795 RuntimeValue::Float(f64::from_le_bytes(b))
5796 }
5797 T_COMPLEXF => {
5798 let re: [u8; 8] = buf.get(*pos..pos.checked_add(8)?)?.try_into().ok()?;
5799 *pos += 8;
5800 let im: [u8; 8] = buf.get(*pos..pos.checked_add(8)?)?.try_into().ok()?;
5801 *pos += 8;
5802 RuntimeValue::ComplexF(Rc::new(logicaffeine_base::ComplexF::new(
5803 f64::from_le_bytes(re),
5804 f64::from_le_bytes(im),
5805 )))
5806 }
5807 T_CHAR => RuntimeValue::Char(char::from_u32(
5808 u32::try_from(read_uvarint(buf, pos)?).ok()?,
5809 )?),
5810 T_TEXT => RuntimeValue::Text(Rc::new(read_str(buf, pos)?)),
5811 T_DURATION => RuntimeValue::Duration(unzigzag(read_uvarint(buf, pos)?)),
5812 T_DATE => RuntimeValue::Date(i32::try_from(unzigzag(read_uvarint(buf, pos)?)).ok()?),
5813 T_MOMENT => RuntimeValue::Moment(unzigzag(read_uvarint(buf, pos)?)),
5814 T_SPAN => RuntimeValue::Span {
5815 months: i32::try_from(unzigzag(read_uvarint(buf, pos)?)).ok()?,
5816 days: i32::try_from(unzigzag(read_uvarint(buf, pos)?)).ok()?,
5817 },
5818 T_TIME => RuntimeValue::Time(unzigzag(read_uvarint(buf, pos)?)),
5819 T_PEER => RuntimeValue::Peer(Rc::new(read_str(buf, pos)?)),
5820 T_LIST => RuntimeValue::List(Rc::new(RefCell::new(ListRepr::Boxed(read_seq(buf, pos)?)))),
5823 T_INTS
5824 | T_INTS_AFFINE
5825 | T_INTS_GEOMETRIC
5826 | T_INTS_PERIODIC
5827 | T_INTS_SPARSE
5828 | T_INTS_POLY
5829 | T_GEN
5830 | T_BYTES
5831 | T_INTS_DELTA
5832 | T_INTS_DOD
5833 | T_INTS_FOR
5834 | T_INTS_RLE
5835 | T_INTS_DICT
5836 | describe::T_INTS_LRECUR
5837 | describe::T_INTS_LFSR
5838 | describe::T_INTS_FCSR => {
5839 let v =
5842 describe::decode_int_column_body(tag, buf, pos, receive_limits().max_elements, 0)?;
5843 RuntimeValue::List(Rc::new(RefCell::new(ListRepr::Ints(v))))
5844 }
5845 T_INTS_GV => RuntimeValue::List(Rc::new(RefCell::new(ListRepr::Ints(gv_decode_dispatch(
5846 buf, pos,
5847 )?)))),
5848 T_FUNC => {
5851 if !receive_limits().accept_computed {
5852 return None;
5853 }
5854 let arity = read_uvarint(buf, pos)? as usize;
5855 if arity > 16 {
5856 return None;
5857 }
5858 let mut budget = MAX_GEN_NODES;
5859 let expr = deserialize_gen(buf, pos, &mut budget, 0)?;
5860 let param_names: Vec<logicaffeine_base::Symbol> = (0..arity)
5861 .map(logicaffeine_base::Symbol::from_index)
5862 .collect();
5863 RuntimeValue::Function(Box::new(ClosureValue {
5864 body_index: usize::MAX,
5865 captured_env: std::collections::HashMap::default(),
5866 param_names,
5867 generated: Some(Rc::new(expr)),
5868 }))
5869 }
5870 T_INTS_FIXED => {
5871 let n = read_uvarint(buf, pos)? as usize;
5872 let nbytes = n.checked_mul(8)?;
5873 let raw = buf.get(*pos..pos.checked_add(nbytes)?)?;
5874 *pos += nbytes;
5875 #[cfg(target_endian = "little")]
5878 let v: Vec<i64> = {
5879 let mut v = Vec::<i64>::with_capacity(n);
5880 unsafe {
5883 std::ptr::copy_nonoverlapping(
5884 raw.as_ptr(),
5885 v.as_mut_ptr().cast::<u8>(),
5886 nbytes,
5887 );
5888 v.set_len(n);
5889 }
5890 v
5891 };
5892 #[cfg(target_endian = "big")]
5893 let v: Vec<i64> = raw
5894 .chunks_exact(8)
5895 .map(|c| i64::from_le_bytes(c.try_into().unwrap()))
5896 .collect();
5897 RuntimeValue::List(Rc::new(RefCell::new(ListRepr::Ints(v))))
5898 }
5899 T_INTS_ALIGNED => {
5901 let n = read_uvarint(buf, pos)? as usize;
5902 let pad = *buf.get(*pos)? as usize;
5903 *pos += 1 + pad;
5904 let nbytes = n.checked_mul(8)?;
5905 let raw = buf.get(*pos..pos.checked_add(nbytes)?)?;
5906 *pos += nbytes;
5907 #[cfg(target_endian = "little")]
5908 let v: Vec<i64> = {
5909 let mut v = Vec::<i64>::with_capacity(n);
5910 unsafe {
5913 std::ptr::copy_nonoverlapping(
5914 raw.as_ptr(),
5915 v.as_mut_ptr().cast::<u8>(),
5916 nbytes,
5917 );
5918 v.set_len(n);
5919 }
5920 v
5921 };
5922 #[cfg(target_endian = "big")]
5923 let v: Vec<i64> = raw
5924 .chunks_exact(8)
5925 .map(|c| i64::from_le_bytes(c.try_into().unwrap()))
5926 .collect();
5927 RuntimeValue::List(Rc::new(RefCell::new(ListRepr::Ints(v))))
5928 }
5929 T_FLOATS => {
5930 let n = bounded_count(read_uvarint(buf, pos)?)?;
5931 let nbytes = n.checked_mul(8)?;
5932 let raw = buf.get(*pos..pos.checked_add(nbytes)?)?;
5933 *pos += nbytes;
5934 #[cfg(target_endian = "little")]
5938 let v: Vec<f64> = {
5939 let mut v = Vec::<f64>::with_capacity(n);
5940 unsafe {
5943 std::ptr::copy_nonoverlapping(
5944 raw.as_ptr(),
5945 v.as_mut_ptr().cast::<u8>(),
5946 nbytes,
5947 );
5948 v.set_len(n);
5949 }
5950 v
5951 };
5952 #[cfg(target_endian = "big")]
5953 let v: Vec<f64> = raw
5954 .chunks_exact(8)
5955 .map(|c| f64::from_le_bytes(c.try_into().unwrap()))
5956 .collect();
5957 RuntimeValue::List(Rc::new(RefCell::new(ListRepr::Floats(v))))
5958 }
5959 T_FLOATS_CONST => {
5961 let bits = u64::from_le_bytes(buf.get(*pos..pos.checked_add(8)?)?.try_into().ok()?);
5962 *pos += 8;
5963 let n = bounded_count(read_uvarint(buf, pos)?)?;
5964 let mut v = Vec::with_capacity(n.min(PREALLOC_CAP));
5965 v.resize(n, f64::from_bits(bits));
5966 RuntimeValue::List(Rc::new(RefCell::new(ListRepr::Floats(v))))
5967 }
5968 T_FLOATS_AFFINE => {
5971 let base = f64::from_le_bytes(buf.get(*pos..pos.checked_add(8)?)?.try_into().ok()?);
5972 *pos += 8;
5973 let stride = f64::from_le_bytes(buf.get(*pos..pos.checked_add(8)?)?.try_into().ok()?);
5974 *pos += 8;
5975 let n = bounded_count(read_uvarint(buf, pos)?)?;
5976 let mut v = Vec::with_capacity(n.min(PREALLOC_CAP));
5977 for i in 0..n {
5978 v.push(base + (i as f64) * stride);
5979 }
5980 RuntimeValue::List(Rc::new(RefCell::new(ListRepr::Floats(v))))
5981 }
5982 T_FLOATS_SPARSE => {
5984 let dom = f64::from_bits(u64::from_le_bytes(
5985 buf.get(*pos..pos.checked_add(8)?)?.try_into().ok()?,
5986 ));
5987 *pos += 8;
5988 let n = bounded_count(read_uvarint(buf, pos)?)?;
5989 let num_exc = bounded_count(read_uvarint(buf, pos)?)?;
5990 let mut v = Vec::with_capacity(n.min(PREALLOC_CAP));
5991 v.resize(n, dom);
5992 let mut idx = 0usize;
5993 for _ in 0..num_exc {
5994 idx = idx.checked_add(read_uvarint(buf, pos)? as usize)?;
5995 let bits = u64::from_le_bytes(buf.get(*pos..pos.checked_add(8)?)?.try_into().ok()?);
5996 *pos += 8;
5997 *v.get_mut(idx)? = f64::from_bits(bits);
5998 }
5999 RuntimeValue::List(Rc::new(RefCell::new(ListRepr::Floats(v))))
6000 }
6001 T_FLOATS_PERIODIC => {
6003 let p = bounded_count(read_uvarint(buf, pos)?)?;
6004 if p == 0 {
6005 return None;
6006 }
6007 let n = bounded_count(read_uvarint(buf, pos)?)?;
6008 let mut block = Vec::with_capacity(p.min(PREALLOC_CAP));
6009 for _ in 0..p {
6010 let bits = u64::from_le_bytes(buf.get(*pos..pos.checked_add(8)?)?.try_into().ok()?);
6011 *pos += 8;
6012 block.push(f64::from_bits(bits));
6013 }
6014 let mut v = Vec::with_capacity(n.min(PREALLOC_CAP));
6015 for i in 0..n {
6016 v.push(block[i % p]);
6017 }
6018 RuntimeValue::List(Rc::new(RefCell::new(ListRepr::Floats(v))))
6019 }
6020 T_FLOATS_GEOMETRIC => {
6023 let base = f64::from_le_bytes(buf.get(*pos..pos.checked_add(8)?)?.try_into().ok()?);
6024 *pos += 8;
6025 let ratio = f64::from_le_bytes(buf.get(*pos..pos.checked_add(8)?)?.try_into().ok()?);
6026 *pos += 8;
6027 let n = bounded_count(read_uvarint(buf, pos)?)?;
6028 let mut v = Vec::with_capacity(n.min(PREALLOC_CAP));
6029 let mut cur = base;
6030 for _ in 0..n {
6031 v.push(cur);
6032 cur *= ratio;
6033 }
6034 RuntimeValue::List(Rc::new(RefCell::new(ListRepr::Floats(v))))
6035 }
6036 T_FLOATS_ALIGNED => {
6038 let n = read_uvarint(buf, pos)? as usize;
6039 let pad = *buf.get(*pos)? as usize;
6040 *pos += 1 + pad;
6041 let nbytes = n.checked_mul(8)?;
6042 let raw = buf.get(*pos..pos.checked_add(nbytes)?)?;
6043 *pos += nbytes;
6044 #[cfg(target_endian = "little")]
6045 let v: Vec<f64> = {
6046 let mut v = Vec::<f64>::with_capacity(n);
6047 unsafe {
6050 std::ptr::copy_nonoverlapping(
6051 raw.as_ptr(),
6052 v.as_mut_ptr().cast::<u8>(),
6053 nbytes,
6054 );
6055 v.set_len(n);
6056 }
6057 v
6058 };
6059 #[cfg(target_endian = "big")]
6060 let v: Vec<f64> = raw
6061 .chunks_exact(8)
6062 .map(|c| f64::from_le_bytes(c.try_into().unwrap()))
6063 .collect();
6064 RuntimeValue::List(Rc::new(RefCell::new(ListRepr::Floats(v))))
6065 }
6066 T_FLOATS_XOR => {
6069 let n = read_uvarint(buf, pos)? as usize;
6070 let mut v = Vec::with_capacity(n.min(PREALLOC_CAP));
6071 let mut prev = 0u64;
6072 for _ in 0..n {
6073 let bits = read_uvarint(buf, pos)? ^ prev;
6074 prev = bits;
6075 v.push(f64::from_bits(bits));
6076 }
6077 RuntimeValue::List(Rc::new(RefCell::new(ListRepr::Floats(v))))
6078 }
6079 T_BOOLS => {
6080 let n = read_uvarint(buf, pos)? as usize;
6081 let nbytes = n.div_ceil(8);
6082 let bits = buf.get(*pos..pos.checked_add(nbytes)?)?;
6083 *pos += nbytes;
6084 let mut v = Vec::with_capacity(n.min(PREALLOC_CAP));
6085 for i in 0..n {
6086 v.push((bits[i / 8] >> (i % 8)) & 1 == 1);
6087 }
6088 RuntimeValue::List(Rc::new(RefCell::new(ListRepr::Bools(v))))
6089 }
6090 T_BOOLS_PERIODIC => {
6092 let p = bounded_count(read_uvarint(buf, pos)?)?;
6093 if p == 0 {
6094 return None;
6095 }
6096 let n = bounded_count(read_uvarint(buf, pos)?)?;
6097 let block_bytes = p.div_ceil(8);
6098 let raw = buf.get(*pos..pos.checked_add(block_bytes)?)?;
6099 *pos += block_bytes;
6100 let block: Vec<bool> = (0..p).map(|i| (raw[i / 8] >> (i % 8)) & 1 == 1).collect();
6101 let mut v = Vec::with_capacity(n.min(PREALLOC_CAP));
6102 for i in 0..n {
6103 v.push(block[i % p]);
6104 }
6105 RuntimeValue::List(Rc::new(RefCell::new(ListRepr::Bools(v))))
6106 }
6107 T_BOOLS_RLE => {
6109 let n = bounded_count(read_uvarint(buf, pos)?)?;
6110 let first = *buf.get(*pos)? != 0;
6111 *pos += 1;
6112 let nruns = bounded_count(read_uvarint(buf, pos)?)?;
6113 let mut v = Vec::with_capacity(n.min(PREALLOC_CAP));
6114 let mut cur = first;
6115 for _ in 0..nruns {
6116 let runlen = bounded_count(read_uvarint(buf, pos)?)?;
6117 if v.len().checked_add(runlen)? > n {
6119 return None;
6120 }
6121 v.resize(v.len() + runlen, cur);
6122 cur = !cur;
6123 }
6124 if v.len() != n {
6125 return None;
6126 }
6127 RuntimeValue::List(Rc::new(RefCell::new(ListRepr::Bools(v))))
6128 }
6129 T_STRINGS => {
6130 let n = read_uvarint(buf, pos)? as usize;
6131 let mut ends = Vec::with_capacity(n.min(PREALLOC_CAP));
6132 let mut total: u64 = 0;
6133 for _ in 0..n {
6134 total = total.checked_add(read_uvarint(buf, pos)?)?;
6135 ends.push(u32::try_from(total).ok()?);
6136 }
6137 let total = usize::try_from(total).ok()?;
6138 let raw = buf.get(*pos..pos.checked_add(total)?)?;
6139 *pos += total;
6140 if std::str::from_utf8(raw).is_err() {
6144 return None;
6145 }
6146 RuntimeValue::List(Rc::new(RefCell::new(ListRepr::strings(raw.to_vec(), ends))))
6147 }
6148 T_STRINGS_TEMPLATE => {
6150 let plen = bounded_count(read_uvarint(buf, pos)?)?;
6151 let prefix = buf.get(*pos..pos.checked_add(plen)?)?.to_vec();
6152 *pos += plen;
6153 let slen = bounded_count(read_uvarint(buf, pos)?)?;
6154 let suffix = buf.get(*pos..pos.checked_add(slen)?)?.to_vec();
6155 *pos += slen;
6156 let base = unzigzag(read_uvarint(buf, pos)?);
6157 let stride = unzigzag(read_uvarint(buf, pos)?);
6158 let n = bounded_count(read_uvarint(buf, pos)?)?;
6159 if std::str::from_utf8(&prefix).is_err() || std::str::from_utf8(&suffix).is_err() {
6161 return None;
6162 }
6163 let mut data = Vec::new();
6164 let mut ends = Vec::with_capacity(n.min(PREALLOC_CAP));
6165 for i in 0..n {
6166 let num = base.wrapping_add((i as i64).wrapping_mul(stride));
6167 data.extend_from_slice(&prefix);
6168 data.extend_from_slice(num.to_string().as_bytes());
6169 data.extend_from_slice(&suffix);
6170 ends.push(u32::try_from(data.len()).ok()?);
6171 }
6172 RuntimeValue::List(Rc::new(RefCell::new(ListRepr::strings(data, ends))))
6173 }
6174 T_STRINGS_FRONT => {
6176 let n = bounded_count(read_uvarint(buf, pos)?)?;
6177 let mut data: Vec<u8> = Vec::new();
6178 let mut ends = Vec::with_capacity(n.min(PREALLOC_CAP));
6179 let mut prev: Vec<u8> = Vec::new();
6180 for _ in 0..n {
6181 let common = bounded_count(read_uvarint(buf, pos)?)?;
6182 let suffix_len = bounded_count(read_uvarint(buf, pos)?)?;
6183 if common > prev.len() {
6185 return None;
6186 }
6187 let suffix = buf.get(*pos..pos.checked_add(suffix_len)?)?;
6188 *pos += suffix_len;
6189 let mut s = Vec::with_capacity(common.checked_add(suffix_len)?);
6190 s.extend_from_slice(&prev[..common]);
6191 s.extend_from_slice(suffix);
6192 data.extend_from_slice(&s);
6193 ends.push(u32::try_from(data.len()).ok()?);
6194 prev = s;
6195 }
6196 if std::str::from_utf8(&data).is_err() {
6199 return None;
6200 }
6201 RuntimeValue::List(Rc::new(RefCell::new(ListRepr::strings(data, ends))))
6202 }
6203 T_STRINGS_AFFIX => {
6205 let plen = bounded_count(read_uvarint(buf, pos)?)?;
6206 let prefix = buf.get(*pos..pos.checked_add(plen)?)?.to_vec();
6207 *pos += plen;
6208 let slen = bounded_count(read_uvarint(buf, pos)?)?;
6209 let suffix = buf.get(*pos..pos.checked_add(slen)?)?.to_vec();
6210 *pos += slen;
6211 let n = bounded_count(read_uvarint(buf, pos)?)?;
6212 let mut data: Vec<u8> = Vec::new();
6213 let mut ends = Vec::with_capacity(n.min(PREALLOC_CAP));
6214 for _ in 0..n {
6215 let mid_len = bounded_count(read_uvarint(buf, pos)?)?;
6216 let mid = buf.get(*pos..pos.checked_add(mid_len)?)?;
6217 *pos += mid_len;
6218 data.extend_from_slice(&prefix);
6219 data.extend_from_slice(mid);
6220 data.extend_from_slice(&suffix);
6221 ends.push(u32::try_from(data.len()).ok()?);
6222 }
6223 if std::str::from_utf8(&data).is_err() {
6225 return None;
6226 }
6227 RuntimeValue::List(Rc::new(RefCell::new(ListRepr::strings(data, ends))))
6228 }
6229 T_STRINGS_DICT => {
6232 let d = read_uvarint(buf, pos)? as usize;
6233 let mut dict: Vec<&[u8]> = Vec::with_capacity(d.min(PREALLOC_CAP));
6234 for _ in 0..d {
6235 let len = read_uvarint(buf, pos)? as usize;
6236 let s = buf.get(*pos..pos.checked_add(len)?)?;
6237 if std::str::from_utf8(s).is_err() {
6238 return None;
6239 }
6240 dict.push(s);
6241 *pos += len;
6242 }
6243 let n = read_uvarint(buf, pos)? as usize;
6244 let iw = *buf.get(*pos)?;
6245 *pos += 1;
6246 if iw > 64 {
6247 return None;
6248 }
6249 let mut out_data: Vec<u8> = Vec::new();
6250 let mut out_ends: Vec<u32> = Vec::with_capacity(n.min(PREALLOC_CAP));
6251 let push = |s: &[u8], out_data: &mut Vec<u8>, out_ends: &mut Vec<u32>| {
6252 out_data.extend_from_slice(s);
6253 out_ends.push(out_data.len() as u32);
6254 };
6255 if iw == 0 {
6256 if n > 0 {
6257 let s = *dict.first()?;
6258 if n.checked_mul(s.len().max(4))? > MAX_DECODE_BYTES {
6262 return None;
6263 }
6264 for _ in 0..n {
6265 push(s, &mut out_data, &mut out_ends);
6266 }
6267 }
6268 } else {
6269 let nbytes = n.checked_mul(iw as usize)?.div_ceil(8);
6270 let bytes = buf.get(*pos..pos.checked_add(nbytes)?)?;
6271 *pos += nbytes;
6272 for ix in bitunpack(bytes, n, iw)? {
6273 push(*dict.get(ix as usize)?, &mut out_data, &mut out_ends);
6274 }
6275 }
6276 RuntimeValue::List(Rc::new(RefCell::new(ListRepr::strings(out_data, out_ends))))
6277 }
6278 T_TUPLE => RuntimeValue::Tuple(Rc::new(read_seq(buf, pos)?)),
6279 T_SET => RuntimeValue::Set(Rc::new(RefCell::new(read_seq(buf, pos)?))),
6280 T_SET_INTS => {
6281 let ints = match native_decode(buf, pos)? {
6284 RuntimeValue::List(l) => l.borrow().to_values(),
6285 _ => return None,
6286 };
6287 RuntimeValue::Set(Rc::new(RefCell::new(ints)))
6288 }
6289 T_SET_STRINGS => {
6290 let n = read_uvarint(buf, pos)? as usize;
6292 let mut items = Vec::with_capacity(n.min(buf.len().saturating_sub(*pos)));
6297 let mut prev = String::new();
6298 for _ in 0..n {
6299 let common = read_uvarint(buf, pos)? as usize;
6300 if common > prev.len() || !prev.is_char_boundary(common) {
6301 return None;
6302 }
6303 let suffix = read_str(buf, pos)?;
6304 let s = format!("{}{}", &prev[..common], suffix);
6305 items.push(RuntimeValue::Text(Rc::new(s.clone())));
6306 prev = s;
6307 }
6308 RuntimeValue::Set(Rc::new(RefCell::new(items)))
6309 }
6310 T_MAP => {
6311 let n = read_uvarint(buf, pos)?;
6312 let mut m = MapStorage::default();
6313 for _ in 0..n {
6314 let k = native_decode(buf, pos)?;
6315 let v = native_decode(buf, pos)?;
6316 m.insert(k, v);
6317 }
6318 RuntimeValue::Map(Rc::new(RefCell::new(m)))
6319 }
6320 T_MAP_INTKEY => {
6321 let keys = match native_decode(buf, pos)? {
6324 RuntimeValue::List(l) => l.borrow().to_values(),
6325 _ => return None,
6326 };
6327 let kind = *buf.get(*pos)?;
6328 *pos += 1;
6329 let vals: Vec<RuntimeValue> = match kind {
6330 1 => match native_decode(buf, pos)? {
6331 RuntimeValue::List(l) => l.borrow().to_values(),
6332 _ => return None,
6333 },
6334 2 => {
6335 let n = read_uvarint(buf, pos)? as usize;
6338 let mut vs = Vec::with_capacity(n.min(keys.len().saturating_add(1)));
6339 let mut prev = String::new();
6340 for _ in 0..n {
6341 let common = read_uvarint(buf, pos)? as usize;
6342 if common > prev.len() || !prev.is_char_boundary(common) {
6343 return None;
6344 }
6345 let suffix = read_str(buf, pos)?;
6346 let s = format!("{}{}", &prev[..common], suffix);
6347 vs.push(RuntimeValue::Text(Rc::new(s.clone())));
6348 prev = s;
6349 }
6350 vs
6351 }
6352 3 => match native_decode(buf, pos)? {
6353 RuntimeValue::List(l) => l.borrow().to_values(),
6355 _ => return None,
6356 },
6357 0 => {
6358 let n = read_uvarint(buf, pos)? as usize;
6359 let mut vs = Vec::with_capacity(n.min(keys.len().saturating_add(1)));
6360 for _ in 0..n {
6361 vs.push(native_decode(buf, pos)?);
6362 }
6363 vs
6364 }
6365 _ => return None,
6366 };
6367 if keys.len() != vals.len() {
6368 return None;
6369 }
6370 let mut m = MapStorage::default();
6371 for (k, v) in keys.into_iter().zip(vals.into_iter()) {
6372 m.insert(k, v);
6373 }
6374 RuntimeValue::Map(Rc::new(RefCell::new(m)))
6375 }
6376 T_STRUCT => {
6377 let type_name = read_str(buf, pos)?;
6378 let n = read_uvarint(buf, pos)?;
6379 let mut fields =
6380 std::collections::HashMap::with_capacity((n as usize).min(PREALLOC_CAP));
6381 for _ in 0..n {
6382 let name = read_str(buf, pos)?;
6383 let val = native_decode(buf, pos)?;
6384 fields.insert(name, val);
6385 }
6386 RuntimeValue::Struct(Box::new(StructValue { type_name, fields }))
6387 }
6388 T_STRUCT_DEF => {
6391 let id = read_uvarint(buf, pos)? as u32;
6392 let (type_name, field_names) = read_struct_schema(buf, pos)?;
6393 if !schema_recv_register_seq(id, &type_name, &field_names) {
6394 return None; }
6396 decode_struct_values(buf, pos, type_name, field_names)?
6397 }
6398 T_STRUCT_REF => {
6401 let id = read_uvarint(buf, pos)? as u32;
6402 let (type_name, field_names) = schema_recv_lookup_seq(id)?;
6403 decode_struct_values(buf, pos, type_name, field_names)?
6404 }
6405 T_STRUCT_CDEF => {
6409 let (type_name, field_names) = read_struct_schema(buf, pos)?;
6410 if !schema_recv_register_ca(&type_name, &field_names) {
6411 return None; }
6413 decode_struct_values(buf, pos, type_name, field_names)?
6414 }
6415 T_STRUCT_CREF => {
6418 let raw = buf.get(*pos..pos.checked_add(8)?)?;
6419 let fp = u64::from_le_bytes(raw.try_into().ok()?);
6420 *pos += 8;
6421 let (type_name, field_names) = schema_recv_lookup_ca(fp)?;
6422 decode_struct_values(buf, pos, type_name, field_names)?
6423 }
6424 T_STRUCT_TID => {
6427 let id = read_uvarint(buf, pos)? as u32;
6428 let (type_name, field_names) = type_registry_schema(id)?;
6429 decode_struct_values(buf, pos, type_name, field_names)?
6430 }
6431 T_STRUCT_VIEW => {
6434 let type_name = read_str(buf, pos)?;
6435 let n = read_uvarint(buf, pos)? as usize;
6436 let mut field_names = Vec::with_capacity(n.min(PREALLOC_CAP));
6437 for _ in 0..n {
6438 field_names.push(read_str(buf, pos)?);
6439 }
6440 *pos = pos.checked_add(n.checked_mul(4)?)?; if *pos > buf.len() {
6442 return None;
6443 }
6444 decode_struct_values(buf, pos, type_name, field_names)?
6445 }
6446 T_STRUCTS_VIEW => {
6450 let type_name = read_str(buf, pos)?;
6451 let f = read_uvarint(buf, pos)? as usize;
6452 let mut field_names = Vec::with_capacity(f.min(PREALLOC_CAP));
6453 for _ in 0..f {
6454 field_names.push(read_str(buf, pos)?);
6455 }
6456 let n = read_uvarint(buf, pos)? as usize;
6457 *pos = pos.checked_add(n.checked_mul(4)?)?; if *pos > buf.len() {
6459 return None;
6460 }
6461 let mut rows = Vec::with_capacity(n.min(PREALLOC_CAP));
6462 for _ in 0..n {
6463 *pos = pos.checked_add(f.checked_mul(4)?)?; if *pos > buf.len() {
6465 return None;
6466 }
6467 rows.push(decode_struct_values(
6468 buf,
6469 pos,
6470 type_name.clone(),
6471 field_names.clone(),
6472 )?);
6473 }
6474 RuntimeValue::List(Rc::new(RefCell::new(ListRepr::from_values(rows))))
6475 }
6476 T_STRUCTS_FVIEW => {
6479 let type_name = read_str(buf, pos)?;
6480 let f = read_uvarint(buf, pos)? as usize;
6481 let mut field_names = Vec::with_capacity(f.min(PREALLOC_CAP));
6482 for _ in 0..f {
6483 field_names.push(read_str(buf, pos)?);
6484 }
6485 let kinds = buf.get(*pos..pos.checked_add(f)?)?.to_vec();
6486 *pos += f;
6487 let n = read_uvarint(buf, pos)? as usize;
6488 let (offsets, stride) = fview_layout(&kinds);
6489 let rows_start = *pos;
6490 let rows_len = n.checked_mul(stride)?;
6491 let rows_bytes = buf.get(rows_start..rows_start.checked_add(rows_len)?)?;
6492 *pos = rows_start.checked_add(rows_len)?;
6493 let blob_len = read_uvarint(buf, pos)? as usize;
6494 let blob = buf.get(*pos..pos.checked_add(blob_len)?)?;
6495 *pos = pos.checked_add(blob_len)?;
6496 let mut columns: Vec<ListRepr> = Vec::with_capacity(f);
6500 for j in 0..f {
6501 let off = offsets[j];
6502 let col = match kinds[j] {
6503 FK_INT => {
6504 let mut v = Vec::with_capacity(n.min(PREALLOC_CAP));
6505 for r in 0..n {
6506 let base = r.checked_mul(stride)?.checked_add(off)?;
6507 v.push(i64::from_le_bytes(
6508 rows_bytes
6509 .get(base..base.checked_add(8)?)?
6510 .try_into()
6511 .ok()?,
6512 ));
6513 }
6514 ListRepr::Ints(v)
6515 }
6516 FK_FLOAT => {
6517 let mut v = Vec::with_capacity(n.min(PREALLOC_CAP));
6518 for r in 0..n {
6519 let base = r.checked_mul(stride)?.checked_add(off)?;
6520 v.push(f64::from_le_bytes(
6521 rows_bytes
6522 .get(base..base.checked_add(8)?)?
6523 .try_into()
6524 .ok()?,
6525 ));
6526 }
6527 ListRepr::Floats(v)
6528 }
6529 FK_BOOL => {
6530 let mut v = Vec::with_capacity(n.min(PREALLOC_CAP));
6531 for r in 0..n {
6532 let base = r.checked_mul(stride)?.checked_add(off)?;
6533 v.push(*rows_bytes.get(base)? != 0);
6534 }
6535 ListRepr::Bools(v)
6536 }
6537 FK_TEXT => {
6538 let mut data: Vec<u8> = Vec::new();
6539 let mut ends: Vec<u32> = Vec::with_capacity(n.min(PREALLOC_CAP));
6540 for r in 0..n {
6541 let base = r.checked_mul(stride)?.checked_add(off)?;
6542 let toff = u32::from_le_bytes(
6543 rows_bytes
6544 .get(base..base.checked_add(4)?)?
6545 .try_into()
6546 .ok()?,
6547 ) as usize;
6548 let tlen = u32::from_le_bytes(
6549 rows_bytes
6550 .get(base.checked_add(4)?..base.checked_add(8)?)?
6551 .try_into()
6552 .ok()?,
6553 ) as usize;
6554 data.extend_from_slice(blob.get(toff..toff.checked_add(tlen)?)?);
6555 ends.push(data.len() as u32);
6556 }
6557 ListRepr::strings(data, ends)
6558 }
6559 _ => return None,
6560 };
6561 columns.push(col);
6562 }
6563 RuntimeValue::List(Rc::new(RefCell::new(ListRepr::Structs {
6564 type_name,
6565 field_names,
6566 columns,
6567 })))
6568 }
6569 T_INDUCTIVE => {
6570 let inductive_type = read_str(buf, pos)?;
6571 let constructor = read_str(buf, pos)?;
6572 let args = read_seq(buf, pos)?;
6573 RuntimeValue::Inductive(std::rc::Rc::new(InductiveValue {
6574 inductive_type,
6575 constructor,
6576 args,
6577 }))
6578 }
6579 T_INDUCTIVE_TID => {
6582 let enum_id = read_uvarint(buf, pos)? as u32;
6583 let ctor_idx = read_uvarint(buf, pos)? as usize;
6584 let (inductive_type, ctors) = type_registry_enum_schema(enum_id)?;
6585 let constructor = ctors.get(ctor_idx)?.clone();
6586 let args = read_seq(buf, pos)?;
6587 RuntimeValue::Inductive(std::rc::Rc::new(InductiveValue {
6588 inductive_type,
6589 constructor,
6590 args,
6591 }))
6592 }
6593 T_STRUCTS => {
6598 let (type_name, field_names) = read_struct_schema(buf, pos)?;
6599 decode_struct_columns(buf, pos, type_name, field_names)?
6600 }
6601 T_STRUCTS_TID => {
6604 let id = read_uvarint(buf, pos)? as u32;
6605 let (type_name, field_names) = type_registry_schema(id)?;
6606 decode_struct_columns(buf, pos, type_name, field_names)?
6607 }
6608 T_STRUCTS_DEF => {
6611 let id = read_uvarint(buf, pos)? as u32;
6612 let (type_name, field_names) = read_struct_schema(buf, pos)?;
6613 if !schema_recv_register_seq(id, &type_name, &field_names) {
6614 return None; }
6616 decode_struct_columns(buf, pos, type_name, field_names)?
6617 }
6618 T_STRUCTS_REF => {
6621 let id = read_uvarint(buf, pos)? as u32;
6622 let (type_name, field_names) = schema_recv_lookup_seq(id)?;
6623 decode_struct_columns(buf, pos, type_name, field_names)?
6624 }
6625 T_STRUCTS_CDEF => {
6629 let (type_name, field_names) = read_struct_schema(buf, pos)?;
6630 if !schema_recv_register_ca(&type_name, &field_names) {
6631 return None; }
6633 decode_struct_columns(buf, pos, type_name, field_names)?
6634 }
6635 T_STRUCTS_CREF => {
6638 let raw = buf.get(*pos..pos.checked_add(8)?)?;
6639 let fp = u64::from_le_bytes(raw.try_into().ok()?);
6640 *pos += 8;
6641 let (type_name, field_names) = schema_recv_lookup_ca(fp)?;
6642 decode_struct_columns(buf, pos, type_name, field_names)?
6643 }
6644 T_INDUCTIVES => {
6649 let inductive_type = read_str(buf, pos)?;
6650 let d = read_uvarint(buf, pos)? as usize;
6651 let mut ctor_dict = Vec::with_capacity(d.min(PREALLOC_CAP));
6652 let mut arities = Vec::with_capacity(d.min(PREALLOC_CAP));
6653 for _ in 0..d {
6654 ctor_dict.push(read_str(buf, pos)?);
6655 arities.push(read_uvarint(buf, pos)? as usize);
6656 }
6657 let idx = match native_decode(buf, pos)? {
6659 RuntimeValue::List(l) => Rc::try_unwrap(l)
6660 .map(RefCell::into_inner)
6661 .unwrap_or_else(|rc| rc.borrow().clone()),
6662 _ => return None,
6663 };
6664 let mut ctors: Vec<u32> = Vec::with_capacity(idx.len().min(PREALLOC_CAP));
6665 for v in idx.to_values() {
6666 match v {
6667 RuntimeValue::Int(i) if i >= 0 && (i as usize) < d => ctors.push(i as u32),
6668 _ => return None,
6669 }
6670 }
6671 let mut arg_cols: Vec<Vec<ListRepr>> = Vec::with_capacity(d.min(PREALLOC_CAP));
6673 for &arity in &arities {
6674 let mut cols = Vec::with_capacity(arity.min(PREALLOC_CAP));
6675 for _ in 0..arity {
6676 let col = match native_decode(buf, pos)? {
6677 RuntimeValue::List(l) => Rc::try_unwrap(l)
6678 .map(RefCell::into_inner)
6679 .unwrap_or_else(|rc| rc.borrow().clone()),
6680 _ => return None,
6681 };
6682 cols.push(col);
6683 }
6684 arg_cols.push(cols);
6685 }
6686 let mut counts = vec![0u32; d];
6688 let mut ranks = Vec::with_capacity(ctors.len());
6689 for &c in &ctors {
6690 ranks.push(counts[c as usize]);
6691 counts[c as usize] += 1;
6692 }
6693 for c in 0..d {
6694 if arg_cols[c]
6695 .iter()
6696 .any(|col| col.len() != counts[c] as usize)
6697 {
6698 return None; }
6700 }
6701 RuntimeValue::List(Rc::new(RefCell::new(ListRepr::Inductives {
6702 inductive_type,
6703 ctor_dict,
6704 ctors,
6705 ranks,
6706 arg_cols,
6707 })))
6708 }
6709 _ => return None,
6710 })
6711}
6712
6713fn read_seq(buf: &[u8], pos: &mut usize) -> Option<Vec<RuntimeValue>> {
6714 let n = bounded_count(read_uvarint(buf, pos)?)?;
6715 let mut v = Vec::with_capacity(n.min(PREALLOC_CAP));
6716 for _ in 0..n {
6717 v.push(native_decode(buf, pos)?);
6718 }
6719 Some(v)
6720}
6721
6722fn read_struct_schema(buf: &[u8], pos: &mut usize) -> Option<(String, Vec<String>)> {
6724 let type_name = read_str(buf, pos)?;
6725 let k = read_uvarint(buf, pos)? as usize;
6726 let mut field_names = Vec::with_capacity(k.min(PREALLOC_CAP));
6727 for _ in 0..k {
6728 field_names.push(read_str(buf, pos)?);
6729 }
6730 Some((type_name, field_names))
6731}
6732
6733fn decode_struct_values(
6736 buf: &[u8],
6737 pos: &mut usize,
6738 type_name: String,
6739 field_names: Vec<String>,
6740) -> Option<RuntimeValue> {
6741 let mut fields = std::collections::HashMap::with_capacity(field_names.len().min(PREALLOC_CAP));
6742 for name in field_names {
6743 let val = native_decode(buf, pos)?;
6744 fields.insert(name, val);
6745 }
6746 Some(RuntimeValue::Struct(Box::new(StructValue {
6747 type_name,
6748 fields,
6749 })))
6750}
6751
6752fn decode_struct_columns(
6757 buf: &[u8],
6758 pos: &mut usize,
6759 type_name: String,
6760 field_names: Vec<String>,
6761) -> Option<RuntimeValue> {
6762 let k = field_names.len();
6763 let n = read_uvarint(buf, pos)? as usize;
6764 let mut columns: Vec<ListRepr> = Vec::with_capacity(k.min(PREALLOC_CAP));
6765 for _ in 0..k {
6766 let col = match native_decode(buf, pos)? {
6770 RuntimeValue::List(l) => Rc::try_unwrap(l)
6771 .map(RefCell::into_inner)
6772 .unwrap_or_else(|rc| rc.borrow().clone()),
6773 _ => return None,
6774 };
6775 if col.len() != n {
6776 return None; }
6778 columns.push(col);
6779 }
6780 Some(if columns.is_empty() {
6781 let rows = (0..n)
6782 .map(|_| {
6783 RuntimeValue::Struct(Box::new(StructValue {
6784 type_name: type_name.clone(),
6785 fields: std::collections::HashMap::new(),
6786 }))
6787 })
6788 .collect();
6789 RuntimeValue::List(Rc::new(RefCell::new(ListRepr::Boxed(rows))))
6790 } else {
6791 RuntimeValue::List(Rc::new(RefCell::new(ListRepr::Structs {
6792 type_name,
6793 field_names,
6794 columns,
6795 })))
6796 })
6797}
6798
6799fn header(codec: WireCodec, integrity: WireIntegrity, compression: WireCompression) -> u8 {
6800 let c = if matches!(codec, WireCodec::Json) {
6801 H_JSON
6802 } else {
6803 0
6804 };
6805 let i = if matches!(integrity, WireIntegrity::Checked) {
6806 H_CHECKED
6807 } else {
6808 0
6809 };
6810 let z = if compression == WireCompression::None {
6811 0
6812 } else {
6813 H_COMPRESSED | (compression_id(compression) << 2)
6814 };
6815 c | i | z
6816}
6817
6818fn frame(
6821 codec: WireCodec,
6822 integrity: WireIntegrity,
6823 compression: WireCompression,
6824 body: Vec<u8>,
6825) -> Vec<u8> {
6826 let h = header(codec, integrity, compression);
6827 match integrity {
6828 WireIntegrity::Raw => {
6829 let mut out = Vec::with_capacity(body.len() + 1);
6830 out.push(h);
6831 out.extend_from_slice(&body);
6832 out
6833 }
6834 WireIntegrity::Checked => {
6835 let mut out = Vec::with_capacity(body.len() + 9);
6836 out.push(h);
6837 out.extend_from_slice(&fnv1a_64(&body).to_le_bytes());
6838 out.extend_from_slice(&body);
6839 out
6840 }
6841 }
6842}
6843
6844fn unframe_with(bytes: &[u8], verify: bool) -> Option<(WireCodec, WireCompression, &[u8])> {
6853 let (&h, rest) = bytes.split_first()?;
6854 if h & !H_KNOWN != 0 {
6855 return None; }
6857 let codec = if h & H_JSON != 0 {
6858 WireCodec::Json
6859 } else {
6860 WireCodec::Native
6861 };
6862 let compression = if h & H_COMPRESSED == 0 {
6863 WireCompression::None
6864 } else {
6865 match (h & H_CODEC) >> 2 {
6866 0 => WireCompression::Deflate,
6867 1 => WireCompression::Lz4,
6868 2 => WireCompression::Zstd,
6869 _ => return None, }
6871 };
6872 let body = if h & H_CHECKED != 0 {
6873 if rest.len() < 8 {
6874 return None;
6875 }
6876 let (sum, body) = rest.split_at(8);
6877 if verify {
6878 let expected = u64::from_le_bytes(sum.try_into().ok()?);
6879 if fnv1a_64(body) != expected {
6880 return None;
6881 }
6882 }
6883 body
6884 } else {
6885 rest
6886 };
6887 Some((codec, compression, body))
6888}
6889
6890fn unframe(bytes: &[u8]) -> Option<(WireCodec, WireCompression, &[u8])> {
6892 unframe_with(bytes, true)
6893}
6894
6895fn fnv1a_64(bytes: &[u8]) -> u64 {
6899 let mut hash = 0xcbf2_9ce4_8422_2325u64;
6900 for &b in bytes {
6901 hash ^= b as u64;
6902 hash = hash.wrapping_mul(0x0000_0100_0000_01b3);
6903 }
6904 hash
6905}
6906
6907pub(crate) fn default_integrity() -> WireIntegrity {
6910 static MODE: std::sync::OnceLock<WireIntegrity> = std::sync::OnceLock::new();
6911 *MODE.get_or_init(|| match std::env::var("LOGOS_WIRE").ok().as_deref() {
6912 Some("raw") => WireIntegrity::Raw,
6913 _ => WireIntegrity::Checked,
6914 })
6915}
6916
6917thread_local! {
6918 static INTEGRITY_OVERRIDE: std::cell::Cell<Option<WireIntegrity>> = const { std::cell::Cell::new(None) };
6919}
6920
6921pub fn with_integrity<T>(integrity: WireIntegrity, f: impl FnOnce() -> T) -> T {
6926 let prev = INTEGRITY_OVERRIDE.with(|c| c.replace(Some(integrity)));
6927 let out = f();
6928 INTEGRITY_OVERRIDE.with(|c| c.set(prev));
6929 out
6930}
6931
6932fn current_integrity() -> WireIntegrity {
6935 INTEGRITY_OVERRIDE
6936 .with(std::cell::Cell::get)
6937 .unwrap_or_else(default_integrity)
6938}
6939
6940fn wire_options() -> impl bincode::Options {
6944 bincode::DefaultOptions::new()
6945}
6946
6947fn canon_bytes(w: &WireValue) -> Vec<u8> {
6950 use bincode::Options;
6951 wire_options().serialize(w).unwrap_or_default()
6952}
6953
6954#[cfg(test)]
6955#[path = "../../../logicaffeine_tests/unit/logicaffeine_compile/concurrency/marshal/tests.rs"]
6956mod tests;