Skip to main content

axsys_noun/
noun.rs

1use crate::{
2    atom::{Atom, Builder as AtomBuilder, Iter as AtomIter},
3    cell::Cell,
4    convert,
5    serdes::{self, Cue, Jam},
6    Rc,
7};
8use std::{
9    collections::HashMap,
10    fmt::{Display, Error, Formatter},
11    mem::drop,
12};
13
14/// An [`Atom`] or a [`Cell`].
15#[derive(Clone, Debug, Eq, Hash, PartialEq)]
16pub enum Noun {
17    /// An arbitrarily large unsigned integer.
18    Atom(Atom),
19    /// A pair of nouns.
20    Cell(Cell),
21}
22
23impl Noun {
24    /// Creates the noun `0`.
25    pub const fn null() -> Self {
26        Self::Atom(Atom::null())
27    }
28
29    /// Returns `true` if this noun is a null atom.
30    pub const fn is_null(&self) -> bool {
31        if let Noun::Atom(atom) = self {
32            atom.is_null()
33        } else {
34            false
35        }
36    }
37
38    /// Computes the hash of this noun.
39    pub fn hash(&self) -> u64 {
40        match self {
41            Self::Atom(atom) => atom.hash(),
42            Self::Cell(cell) => cell.hash(),
43        }
44    }
45
46    pub fn as_cell(&self) -> Option<&Cell> {
47        if let Noun::Cell(cell) = self {
48            Some(cell)
49        } else {
50            None
51        }
52    }
53
54    pub fn into_atom(&self) -> Option<Atom> {
55        if let Noun::Atom(atom) = self {
56            Some(atom.clone())
57        } else {
58            None
59        }
60    }
61
62    pub fn into_cell(&self) -> Option<Cell> {
63        if let Noun::Cell(cell) = self {
64            Some(cell.clone())
65        } else {
66            None
67        }
68    }
69
70    pub fn as_atom(&self) -> Option<&Atom> {
71        if let Noun::Atom(atom) = self {
72            Some(atom)
73        } else {
74            None
75        }
76    }
77}
78
79impl Cue for Noun {
80    fn cue(jammed_noun: Atom) -> serdes::Result<Self> {
81        fn decode_atom(bits: &mut AtomIter) -> serdes::Result<Atom> {
82            let len = {
83                let mut len_of_len = 0;
84                loop {
85                    match bits.next() {
86                        Some(true) => break,
87                        Some(false) => len_of_len += 1,
88                        None => return Err(serdes::Error::InvalidLen),
89                    }
90                }
91
92                if len_of_len == 0 {
93                    0
94                } else {
95                    // The most significant bit of the length is implicit because it's always 1.
96                    let len_bits = len_of_len - 1;
97                    let mut len: u64 = 1 << len_bits;
98                    for i in 0..len_bits {
99                        match bits.next() {
100                            Some(true) => len |= 1 << i,
101                            Some(false) => len &= !(1 << i),
102                            None => return Err(serdes::Error::InvalidLen),
103                        }
104                    }
105                    len
106                }
107            };
108            if len == 0 {
109                Ok(Atom::from(0u8))
110            } else {
111                let mut atom_builder = Atom::builder();
112                for _ in 0..len {
113                    let bit = bits.next().ok_or(serdes::Error::AtomBuilding)?;
114                    atom_builder.push_bit(bit);
115                }
116                Ok(atom_builder.into_atom())
117            }
118        }
119
120        fn decode(
121            bits: &mut AtomIter,
122            cache: &mut HashMap<u64, Rc<Noun>>,
123        ) -> serdes::Result<Rc<Noun>> {
124            let pos = bits.pos() as u64;
125            match bits.next() {
126                Some(true) => {
127                    match bits.next() {
128                        // Back reference tag = 0b11.
129                        Some(true) => {
130                            let idx = decode_atom(bits)?
131                                .as_u64()
132                                .ok_or(serdes::Error::InvalidBackref)?;
133                            let noun = cache.get(&idx).ok_or(serdes::Error::CacheMiss)?;
134                            Ok(noun.clone())
135                        }
136                        // Cell tag = 0b01.
137                        Some(false) => {
138                            let head = decode(bits, cache)?;
139                            let tail = decode(bits, cache)?;
140
141                            let cell = Rc::<Noun>::from(Cell::from([head, tail]));
142                            cache.insert(pos, cell.clone());
143
144                            Ok(cell)
145                        }
146                        None => Err(serdes::Error::InvalidTag),
147                    }
148                }
149                // Atom tag = 0b0.
150                Some(false) => {
151                    let atom = Rc::<Noun>::from(decode_atom(bits)?);
152                    cache.insert(pos, atom.clone());
153                    Ok(atom)
154                }
155                None => unimplemented!(),
156            }
157        }
158
159        let mut bits = jammed_noun.iter();
160        let mut cache = HashMap::new();
161        let noun = decode(&mut bits, &mut cache)?;
162        // Dropping the cache guarantees that the top level noun has exactly one reference, which
163        // makes it safe to move out of the Rc.
164        drop(cache);
165        let noun = Rc::try_unwrap(noun).unwrap();
166        Ok(noun)
167    }
168}
169
170impl Display for Noun {
171    fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), Error> {
172        match self {
173            Self::Atom(atom) => atom.fmt(f),
174            Self::Cell(cell) => cell.fmt(f),
175        }
176    }
177}
178
179impl From<Atom> for Noun {
180    fn from(atom: Atom) -> Self {
181        Self::Atom(atom)
182    }
183}
184
185impl From<Atom> for Rc<Noun> {
186    fn from(atom: Atom) -> Self {
187        Rc::new(Noun::Atom(atom))
188    }
189}
190
191impl From<Cell> for Noun {
192    fn from(cell: Cell) -> Self {
193        Self::Cell(cell)
194    }
195}
196
197impl From<Cell> for Rc<Noun> {
198    fn from(cell: Cell) -> Self {
199        Rc::new(Noun::Cell(cell))
200    }
201}
202
203impl Jam for Noun {
204    fn jam(self) -> Atom {
205        fn encode_len(mut len: u64, bits: &mut AtomBuilder) {
206            let len_of_len = u64::BITS - len.leading_zeros();
207            for _ in 0..len_of_len {
208                bits.push_bit(false);
209            }
210            bits.push_bit(true);
211            if len_of_len != 0 {
212                // Don't write the most significant bit of the length because it's always 1.
213                while len != 1 {
214                    bits.push_bit((len & 1) != 0);
215                    len >>= 1;
216                }
217            }
218        }
219
220        fn encode_atom(atom: &Atom, bits: &mut AtomBuilder) {
221            // Atom tag = 0b0.
222            bits.push_bit(false);
223            encode_len(atom.bit_len() as u64, bits);
224            for bit in atom.iter() {
225                bits.push_bit(bit);
226            }
227        }
228
229        fn encode(noun: Rc<Noun>, bits: &mut AtomBuilder, cache: &mut HashMap<Rc<Noun>, u64>) {
230            if let Some(idx) = cache.get(&noun) {
231                if let Noun::Atom(ref atom) = *noun {
232                    let idx_bit_len = u64::from(u64::BITS - idx.leading_zeros());
233                    let atom_bit_len = atom.bit_len() as u64;
234                    // Backreferences to atoms are only encoded if they're shorter than the atom it
235                    // would reference.
236                    if atom_bit_len <= idx_bit_len {
237                        encode_atom(atom, bits);
238                        return;
239                    }
240                }
241                let idx = Atom::from(*idx);
242                // Backreference tag = 0b11.
243                bits.push_bit(true);
244                bits.push_bit(true);
245                encode_len(idx.bit_len() as u64, bits);
246                for bit in idx.iter() {
247                    bits.push_bit(bit);
248                }
249                return;
250            }
251
252            cache.insert(noun.clone(), bits.pos() as u64);
253            match *noun {
254                Noun::Atom(ref atom) => encode_atom(atom, bits),
255                Noun::Cell(ref cell) => {
256                    // Cell tag = 0b01.
257                    bits.push_bit(true);
258                    bits.push_bit(false);
259                    encode(cell.head(), bits, cache);
260                    encode(cell.tail(), bits, cache);
261                }
262            }
263        }
264
265        let noun = Rc::new(self);
266        let mut bits = Atom::builder();
267        let mut cache = HashMap::new();
268        encode(noun, &mut bits, &mut cache);
269        bits.into_atom()
270    }
271}
272
273impl TryFrom<&&str> for Noun {
274    type Error = ();
275
276    fn try_from(string: &&str) -> Result<Self, Self::Error> {
277        Ok(Noun::from(Atom::from(*string)))
278    }
279}
280
281impl TryFrom<String> for Noun {
282    type Error = ();
283
284    fn try_from(string: String) -> Result<Self, Self::Error> {
285        Ok(Noun::from(Atom::from(string)))
286    }
287}
288
289impl<'a> TryFrom<&'a Noun> for &'a str {
290    type Error = convert::Error;
291
292    fn try_from(noun: &'a Noun) -> Result<Self, Self::Error> {
293        if let Noun::Atom(noun) = noun {
294            noun.as_str().or(Err(convert::Error::AtomToStr))
295        } else {
296            Err(convert::Error::UnexpectedCell)
297        }
298    }
299}
300
301impl TryFrom<&Noun> for String {
302    type Error = convert::Error;
303
304    fn try_from(noun: &Noun) -> Result<Self, Self::Error> {
305        if let Noun::Atom(noun) = noun {
306            if let Ok(noun) = noun.as_str() {
307                Ok(Self::from(noun))
308            } else {
309                Err(convert::Error::AtomToStr)
310            }
311        } else {
312            Err(convert::Error::UnexpectedCell)
313        }
314    }
315}
316
317#[cfg(feature = "thread-safe")]
318unsafe impl Send for Noun {}
319
320#[cfg(feature = "thread-safe")]
321unsafe impl Sync for Noun {}
322
323#[cfg(test)]
324mod tests {
325    use super::*;
326
327    #[test]
328    fn jam_cue_atom() {
329        // 0 serializes to 2.
330        {
331            let atom: Noun = Noun::from(Atom::from(0u8));
332            let jammed_atom = Atom::from(2u8);
333            assert_eq!(atom.clone().jam(), jammed_atom);
334            assert_eq!(Noun::cue(jammed_atom).expect("cue"), atom);
335        }
336
337        // 1 serializes to 12.
338        {
339            let atom: Noun = Noun::from(Atom::from(1u8));
340            let jammed_atom = Atom::from(12u8);
341            assert_eq!(atom.clone().jam(), jammed_atom);
342            assert_eq!(Noun::cue(jammed_atom).expect("cue"), atom);
343        }
344
345        // 2 serializes to 72.
346        {
347            let atom: Noun = Noun::from(Atom::from(2u8));
348            let jammed_atom = Atom::from(72u8);
349            assert_eq!(atom.clone().jam(), jammed_atom);
350            assert_eq!(Noun::cue(jammed_atom).expect("cue"), atom);
351        }
352
353        // 19 serializes to 2480.
354        {
355            let atom: Noun = Noun::from(Atom::from(19u8));
356            let jammed_atom = Atom::from(2480u16);
357            assert_eq!(atom.clone().jam(), jammed_atom);
358            assert_eq!(Noun::cue(jammed_atom).expect("cue"), atom);
359        }
360
361        // 581.949.002 serializes to 1.191.831.557.952.
362        {
363            let atom: Noun = Noun::from(Atom::from(581_949_002u32));
364            let jammed_atom = Atom::from(1_191_831_557_952u64);
365            assert_eq!(atom.clone().jam(), jammed_atom);
366            assert_eq!(Noun::cue(jammed_atom).expect("cue"), atom);
367        }
368    }
369
370    #[test]
371    fn jam_cue_cell() {
372        // [0 19] serializes into 39.689.
373        {
374            let cell: Noun = Noun::from(Cell::from([0u8, 19u8]));
375            let jammed_cell = Atom::from(39_689u16);
376            assert_eq!(cell.clone().jam(), jammed_cell);
377            assert_eq!(Noun::cue(jammed_cell).expect("cue"), cell);
378        }
379
380        // [1 1] serializes to 817.
381        {
382            let cell: Noun = Noun::from(Cell::from([1u8, 1u8]));
383            let jammed_cell = Atom::from(817u16);
384            assert_eq!(cell.clone().jam(), jammed_cell);
385            assert_eq!(Noun::cue(jammed_cell).expect("cue"), cell);
386        }
387
388        // [10.000 10.000] serializes into 4.952.983.169.
389        {
390            let cell: Noun = Noun::from(Cell::from([10_000u16, 10_000u16]));
391            let jammed_cell = Atom::from(0b100100111001110001000011010000001u64);
392            assert_eq!(cell.clone().jam(), jammed_cell);
393            assert_eq!(Noun::cue(jammed_cell).expect("cue"), cell);
394        }
395
396        // [999.999.999 999.999.999] serializes to 1.301.217.674.263.809.
397        {
398            let cell: Noun = Noun::from(Cell::from([999_999_999u32, 999_999_999u32]));
399            let jammed_cell = Atom::from(0b100100111110111001101011001001111111111110100000001u64);
400            assert_eq!(cell.clone().jam(), jammed_cell);
401            assert_eq!(Noun::cue(jammed_cell).expect("cue"), cell);
402        }
403
404        // [222 444 888] serializes to 250.038.217.192.960.129.
405        {
406            let cell: Noun = Noun::from(Cell::from([222u16, 444u16, 888u16]));
407            let jammed_cell = Atom::from(250_038_217_192_960_129u64);
408            assert_eq!(cell.clone().jam(), jammed_cell);
409            assert_eq!(Noun::cue(jammed_cell).expect("cue"), cell);
410        }
411
412        // [[107 110] [107 110]] serializes to 635.080.761.093.
413        {
414            let head = Rc::<Noun>::from(Cell::from([107u8, 110u8]));
415            let cell: Noun = Noun::from(Cell::from([head.clone(), head]));
416            let jammed_cell = Atom::from(0b1001001111011101110000110101111100000101u64);
417            assert_eq!(cell.clone().jam(), jammed_cell);
418            assert_eq!(Noun::cue(jammed_cell).expect("cue"), cell);
419        }
420
421        // [0 1 2 3 4 5 6 7 8 9 10] serializes to 25.681.224.503.728.653.597.984.370.231.065.
422        {
423            let cell: Noun = Noun::from(Cell::from([
424                0u8, 1u8, 2u8, 3u8, 4u8, 5u8, 6u8, 7u8, 8u8, 9u8, 10u8,
425            ]));
426
427            let jammed_cell = Atom::from(25_681_224_503_728_653_597_984_370_231_065u128);
428            assert_eq!(cell.clone().jam(), jammed_cell);
429            assert_eq!(Noun::cue(jammed_cell).expect("cue"), cell);
430        }
431
432        // [99 100 101 102 103 104 0] serializes to 223.372.995.869.285.333.705.242.560.449.
433        {
434            let cell: Noun = Noun::from(Cell::from([99u8, 100u8, 101u8, 102u8, 103u8, 104u8, 0u8]));
435            let jammed_cell = Atom::from(223_372_995_869_285_333_705_242_560_449u128);
436            assert_eq!(cell.clone().jam(), jammed_cell);
437            assert_eq!(Noun::cue(jammed_cell).expect("cue"), cell);
438        }
439
440        // [[222 444 888] [222 444 888]] serializes to 170.479.614.045.978.345.989.
441        {
442            let head = Rc::<Noun>::from(Cell::from([222u16, 444u16, 888u16]));
443            let cell: Noun = Noun::from(Cell::from([head.clone(), head]));
444            let jammed_cell = Atom::from(170_479_614_045_978_345_989u128);
445            assert_eq!(cell.clone().jam(), jammed_cell);
446            assert_eq!(Noun::cue(jammed_cell).expect("cue"), cell);
447        }
448
449        // [[0 1] [1 2] [2 3] [3 4] 0] serializes to 11.976.248.475.217.237.797.
450        {
451            let cell: Noun = Noun::from(Cell::from([
452                Noun::from(Cell::from([0u8, 1u8])),
453                Noun::from(Cell::from([1u8, 2u8])),
454                Noun::from(Cell::from([2u8, 3u8])),
455                Noun::from(Cell::from([3u8, 4u8])),
456                Noun::from(Atom::from(0u8)),
457            ]));
458            let jammed_cell = Atom::from(11_976_248_475_217_237_797u64);
459            assert_eq!(cell.clone().jam(), jammed_cell);
460            assert_eq!(Noun::cue(jammed_cell).expect("cue"), cell);
461        }
462
463        // [[0 1] [1 2] [2 3] [3 4] [4 5] [5 6] [6 7] [7 8] [8 9] 0] serializes to
464        // 7.694.087.033.387.855.647.747.387.855.514.468.399.947.749.137.782.565.
465        {
466            let cell: Noun = Noun::from(Cell::from([
467                Noun::from(Cell::from([0u8, 1u8])),
468                Noun::from(Cell::from([1u8, 2u8])),
469                Noun::from(Cell::from([2u8, 3u8])),
470                Noun::from(Cell::from([3u8, 4u8])),
471                Noun::from(Cell::from([4u8, 5u8])),
472                Noun::from(Cell::from([5u8, 6u8])),
473                Noun::from(Cell::from([6u8, 7u8])),
474                Noun::from(Cell::from([7u8, 8u8])),
475                Noun::from(Cell::from([8u8, 9u8])),
476                Noun::from(Atom::from(0u8)),
477            ]));
478            let jammed_cell = Atom::from(vec![
479                37, 23, 35, 11, 137, 46, 52, 102, 97, 226, 22, 46, 118, 97, 227, 23, 62, 4, 11,
480                130, 144, 20,
481            ]);
482            assert_eq!(cell.clone().jam(), jammed_cell);
483            assert_eq!(Noun::cue(jammed_cell).expect("cue"), cell);
484        }
485
486        // [[0 1] [2 3] [4 5] [6 7] [8 9] [10 11] [12 13] [14 15] [16 17] [18 19] [20 21] 0]
487        // serializes to
488        // 308.947.677.754.874.070.959.300.747.182.056.036.528.545.493.781.368.831.595.479.491.505.523.344.414.501.
489        {
490            let cell: Noun = Noun::from(Cell::from([
491                Noun::from(Cell::from([0u8, 1u8])),
492                Noun::from(Cell::from([2u8, 3u8])),
493                Noun::from(Cell::from([4u8, 5u8])),
494                Noun::from(Cell::from([6u8, 7u8])),
495                Noun::from(Cell::from([8u8, 9u8])),
496                Noun::from(Cell::from([10u8, 11u8])),
497                Noun::from(Cell::from([12u8, 13u8])),
498                Noun::from(Cell::from([14u8, 15u8])),
499                Noun::from(Cell::from([16u8, 17u8])),
500                Noun::from(Cell::from([18u8, 19u8])),
501                Noun::from(Cell::from([20u8, 21u8])),
502                Noun::from(Atom::from(0u8)),
503            ]));
504            let jammed_cell = Atom::from(vec![
505                37, 23, 18, 93, 152, 184, 133, 141, 95, 16, 132, 100, 65, 20, 178, 5, 97, 72, 23,
506                196, 33, 95, 48, 8, 139, 5, 147, 176, 89, 48, 10, 171, 2,
507            ]);
508            assert_eq!(cell.clone().jam(), jammed_cell);
509            assert_eq!(Noun::cue(jammed_cell).expect("cue"), cell);
510        }
511
512        // [[%vary 'Origin'] [%vary 'Accept-Encoding']] serializes to
513        // 2.923.956.498.268.356.738.336.949.786.175.643.457.788.180.560.108.194.340.456.079.961.920.720.567.301.
514        {
515            let cell: Noun = Noun::from(Cell::from([
516                Cell::from(["vary", "Origin"]),
517                Cell::from(["vary", "Accept-Encoding"]),
518            ]));
519            let jammed_cell = Atom::from(vec![
520                5, 124, 187, 48, 185, 60, 224, 123, 146, 75, 59, 75, 115, 55, 19, 224, 29, 52, 54,
521                86, 6, 71, 215, 82, 228, 54, 246, 70, 150, 230, 118, 6,
522            ]);
523            assert_eq!(cell.clone().jam(), jammed_cell);
524            assert_eq!(Noun::cue(jammed_cell).expect("cue"), cell);
525        }
526
527        // [%x-cached 'HIT'] serializes to 3.419.056.981.361.227.851.413.339.139.505.665.
528        {
529            let cell: Noun = Noun::from(Cell::from(["x-cached", "HIT"]));
530            let jammed_cell = Atom::from(3_419_056_981_361_227_851_413_339_139_505_665u128);
531            assert_eq!(cell.clone().jam(), jammed_cell);
532            assert_eq!(Noun::cue(jammed_cell).expect("cue"), cell);
533        }
534
535        // [
536        //  [%x-cached 'HIT']
537        //  [%vary 'Origin']
538        //  [%vary 'Accept-Encoding']
539        //  0
540        // ]
541        // serializes to
542        // 54.024.941.019.988.598.271.402.968.678.037.641.784.219.129.665.004.500.606.995.034.380.342.041.694.044.032.862.185.742.959.381.716.818.503.067.105.285.
543        {
544            let cell: Noun = Noun::from(Cell::from([
545                Noun::from(Cell::from(["x-cached", "HIT"])),
546                Noun::from(Cell::from(["vary", "Origin"])),
547                Noun::from(Cell::from(["vary", "Accept-Encoding"])),
548                Noun::from(Atom::from(0u8)),
549            ]));
550            let jammed_cell = Atom::from(vec![
551                5, 248, 241, 90, 198, 194, 198, 208, 202, 200, 192, 67, 74, 162, 22, 240, 237, 194,
552                228, 242, 128, 239, 73, 46, 237, 44, 205, 93, 227, 118, 128, 119, 208, 216, 88, 25,
553                28, 93, 75, 145, 219, 216, 27, 89, 154, 219, 89,
554            ]);
555            assert_eq!(cell.clone().jam(), jammed_cell);
556            assert_eq!(Noun::cue(jammed_cell).expect("cue"), cell);
557        }
558
559        // [
560        //  [%x-cached 'HIT']
561        //  [%vary 'Origin']
562        //  [%vary 'Accept-Encoding']
563        //  [%connection %keep-alive]
564        //  0
565        // ]
566        // serializes to
567        // 337.262.554.346.536.272.809.263.434.776.769.507.747.563.642.163.274.356.590.866.601.381.185.210.047.197.602.041.291.492.349.359.710.146.253.456.410.124.597.539.747.968.329.210.676.233.756.528.621.237.772.236.684.881.982.257.157.
568        {
569            let cell: Noun = Noun::from(Cell::from([
570                Noun::from(Cell::from(["x-cached", "HIT"])),
571                Noun::from(Cell::from(["vary", "Origin"])),
572                Noun::from(Cell::from(["vary", "Accept-Encoding"])),
573                Noun::from(Cell::from(["connection", "keep-alive"])),
574                Noun::from(Atom::from(0u8)),
575            ]));
576            let jammed_cell = Atom::from(vec![
577                5, 248, 241, 90, 198, 194, 198, 208, 202, 200, 192, 67, 74, 162, 22, 240, 237, 194,
578                228, 242, 128, 239, 73, 46, 237, 44, 205, 93, 227, 118, 128, 119, 208, 216, 88, 25,
579                28, 93, 75, 145, 219, 216, 27, 89, 154, 219, 185, 0, 62, 99, 111, 110, 110, 101,
580                99, 116, 105, 111, 110, 128, 207, 90, 89, 25, 92, 75, 24, 91, 154, 93, 89,
581            ]);
582            assert_eq!(cell.clone().jam(), jammed_cell);
583            assert_eq!(Noun::cue(jammed_cell).expect("cue"), cell);
584        }
585
586        // [
587        //  [%x-cached 'HIT']
588        //  [%vary 'Origin']
589        //  [%vary 'Accept-Encoding']
590        //  [%connection %keep-alive]
591        //  [%content-length '59']
592        //  0
593        // ]
594        // serializes to
595        // 3.990.449.691.910.602.529.066.905.532.683.432.376.481.595.709.178.878.504.454.195.556.485.477.933.263.285.640.666.005.735.466.251.842.927.155.004.960.860.680.532.900.649.099.981.551.377.940.562.846.107.819.739.708.673.550.687.574.046.762.646.573.624.712.055.218.066.331.781.777.383.880.709.
596        {
597            let cell: Noun = Noun::from(Cell::from([
598                Noun::from(Cell::from(["x-cached", "HIT"])),
599                Noun::from(Cell::from(["vary", "Origin"])),
600                Noun::from(Cell::from(["vary", "Accept-Encoding"])),
601                Noun::from(Cell::from(["connection", "keep-alive"])),
602                Noun::from(Cell::from(["content-length", "59"])),
603                Noun::from(Atom::from(0u8)),
604            ]));
605
606            let jammed_cell = Atom::from(vec![
607                5, 248, 241, 90, 198, 194, 198, 208, 202, 200, 192, 67, 74, 162, 22, 240, 237, 194,
608                228, 242, 128, 239, 73, 46, 237, 44, 205, 93, 227, 118, 128, 119, 208, 216, 88, 25,
609                28, 93, 75, 145, 219, 216, 27, 89, 154, 219, 185, 0, 62, 99, 111, 110, 110, 101,
610                99, 116, 105, 111, 110, 128, 207, 90, 89, 25, 92, 75, 24, 91, 154, 93, 185, 0, 190,
611                99, 111, 110, 116, 101, 110, 116, 45, 108, 101, 110, 103, 116, 104, 208, 53, 185,
612            ]);
613            assert_eq!(cell.clone().jam(), jammed_cell);
614            assert_eq!(Noun::cue(jammed_cell).expect("cue"), cell);
615        }
616
617        // [
618        //  [%x-cached 'HIT']
619        //  [%vary 'Origin']
620        //  [%vary 'Accept-Encoding']
621        //  [%connection %keep-alive]
622        //  [%content-length '59']
623        //  [%content-type 'application/json']
624        //  0
625        // ]
626        // serializes to
627        // 457.091.532.517.554.390.786.006.469.499.335.612.968.565.672.928.161.381.020.311.663.688.274.027.085.520.617.498.455.482.250.967.104.025.408.758.206.722.076.439.600.215.410.221.147.402.178.087.201.942.131.610.143.956.380.101.670.231.516.755.661.365.800.622.895.086.504.659.989.465.932.175.163.419.593.361.271.135.450.933.952.288.380.655.088.063.544.328.215.173.068.577.627.294.732.347.635.717.
628        {
629            let cell: Noun = Noun::from(Cell::from([
630                Noun::from(Cell::from(["x-cached", "HIT"])),
631                Noun::from(Cell::from(["vary", "Origin"])),
632                Noun::from(Cell::from(["vary", "Accept-Encoding"])),
633                Noun::from(Cell::from(["connection", "keep-alive"])),
634                Noun::from(Cell::from(["content-length", "59"])),
635                Noun::from(Cell::from(["content-type", "application/json"])),
636                Noun::from(Atom::from(0u8)),
637            ]));
638
639            let jammed_cell = Atom::from(vec![
640                5, 248, 241, 90, 198, 194, 198, 208, 202, 200, 192, 67, 74, 162, 22, 240, 237, 194,
641                228, 242, 128, 239, 73, 46, 237, 44, 205, 93, 227, 118, 128, 119, 208, 216, 88, 25,
642                28, 93, 75, 145, 219, 216, 27, 89, 154, 219, 185, 0, 62, 99, 111, 110, 110, 101,
643                99, 116, 105, 111, 110, 128, 207, 90, 89, 25, 92, 75, 24, 91, 154, 93, 185, 0, 190,
644                99, 111, 110, 116, 101, 110, 116, 45, 108, 101, 110, 103, 116, 104, 208, 53, 121,
645                1, 252, 198, 222, 220, 232, 202, 220, 232, 90, 232, 242, 224, 202, 0, 255, 48, 56,
646                56, 182, 180, 177, 48, 186, 180, 55, 183, 23, 181, 185, 55, 183,
647            ]);
648            assert_eq!(cell.clone().jam(), jammed_cell);
649            assert_eq!(Noun::cue(jammed_cell).expect("cue"), cell);
650        }
651
652        // [
653        //  [%x-cached 'HIT']
654        //  [%vary 'Origin']
655        //  [%vary 'Accept-Encoding']
656        //  [%connection %keep-alive]
657        //  [%content-length '59']
658        //  [%content-type 'application/json']
659        //  [%date 'Fri, 08 Jul 2022 16:43:50 GMT']
660        //  0
661        // ]
662        // serializes to
663        // 13.511.042.605.182.938.704.141.471.102.024.299.594.955.332.558.307.008.475.497.880.712.859.675.484.538.257.353.584.918.969.851.530.816.463.453.015.799.780.201.687.994.505.320.116.239.292.288.026.317.441.863.373.121.089.158.775.350.462.009.180.764.811.763.710.140.560.982.428.678.690.500.900.830.579.867.363.560.770.528.863.245.324.334.716.215.913.775.596.115.997.818.308.278.262.023.037.514.343.972.996.368.914.301.576.422.996.306.770.335.657.447.377.076.271.378.523.965.990.245.753.334.799.571.283.621.312.517.
664        {
665            let cell: Noun = Noun::from(Cell::from([
666                Noun::from(Cell::from(["x-cached", "HIT"])),
667                Noun::from(Cell::from(["vary", "Origin"])),
668                Noun::from(Cell::from(["vary", "Accept-Encoding"])),
669                Noun::from(Cell::from(["connection", "keep-alive"])),
670                Noun::from(Cell::from(["content-length", "59"])),
671                Noun::from(Cell::from(["content-type", "application/json"])),
672                Noun::from(Cell::from(["date", "Fri, 08 Jul 2022 16:43:50 GMT"])),
673                Noun::from(Atom::from(0u8)),
674            ]));
675
676            let jammed_cell = Atom::from(vec![
677                5, 248, 241, 90, 198, 194, 198, 208, 202, 200, 192, 67, 74, 162, 22, 240, 237, 194,
678                228, 242, 128, 239, 73, 46, 237, 44, 205, 93, 227, 118, 128, 119, 208, 216, 88, 25,
679                28, 93, 75, 145, 219, 216, 27, 89, 154, 219, 185, 0, 62, 99, 111, 110, 110, 101,
680                99, 116, 105, 111, 110, 128, 207, 90, 89, 25, 92, 75, 24, 91, 154, 93, 185, 0, 190,
681                99, 111, 110, 116, 101, 110, 116, 45, 108, 101, 110, 103, 116, 104, 208, 53, 121,
682                1, 252, 198, 222, 220, 232, 202, 220, 232, 90, 232, 242, 224, 202, 0, 255, 48, 56,
683                56, 182, 180, 177, 48, 186, 180, 55, 183, 23, 181, 185, 55, 119, 1, 159, 44, 140,
684                174, 12, 224, 217, 72, 46, 141, 5, 4, 6, 7, 68, 169, 142, 13, 68, 6, 70, 70, 6, 36,
685                198, 70, 135, 102, 70, 167, 6, 6, 228, 168, 137, 42,
686            ]);
687            assert_eq!(cell.clone().jam(), jammed_cell);
688            assert_eq!(Noun::cue(jammed_cell).expect("cue"), cell);
689        }
690
691        //  [%server 'nginx/1.14.0 (Ubuntu)'] serializes to
692        //  36.625.686.482.471.374.629.531.055.727.019.932.223.514.833.888.924.393.604.670.670.633.971.596.801.
693        {
694            let cell: Noun = Noun::from(Cell::from(["server", "nginx/1.14.0 (Ubuntu)"]));
695            let jammed_cell = Atom::from(vec![
696                1, 190, 185, 50, 57, 187, 50, 57, 128, 38, 183, 179, 52, 55, 188, 151, 24, 151, 24,
697                26, 23, 24, 16, 148, 42, 177, 58, 55, 186, 186, 20,
698            ]);
699            assert_eq!(cell.clone().jam(), jammed_cell);
700            assert_eq!(Noun::cue(jammed_cell).expect("cue"), cell);
701        }
702
703        // (jam [[%x-cached 'HIT'] [%vary 'Origin'] [%vary 'Accept-Encoding'] [%connection %keep-alive] [%content-length '59'] [%content-type 'application/json'] [%date 'Fri, 08 Jul 2022 16:43:50 GMT'] [%server 'nginx/1.14.0 (Ubuntu)'] 0])
704        // [
705        //  [%x-cached 'HIT']
706        //  [%vary 'Origin']
707        //  [%vary 'Accept-Encoding']
708        //  [%connection %keep-alive]
709        //  [%content-length '59']
710        //  [%content-type 'application/json']
711        //  [%date 'Fri, 08 Jul 2022 16:43:50 GMT']
712        //  [%server 'nginx/1.14.0 (Ubuntu)']
713        //  0
714        // ]
715        // serializes to
716        // 3.043.179.738.672.136.626.575.394.190.673.759.579.727.849.692.505.022.485.010.845.918.679.803.129.305.613.240.481.085.317.833.394.833.266.220.825.965.186.842.937.880.270.236.914.729.803.832.464.269.764.501.574.488.877.790.107.593.782.177.681.982.718.127.995.102.131.872.994.171.509.635.987.438.144.206.782.752.956.394.374.740.266.989.132.241.617.591.666.709.510.062.224.526.419.612.002.666.485.664.696.539.844.896.863.868.458.496.893.612.588.610.229.380.812.024.688.103.535.216.455.403.528.290.497.755.248.780.777.953.932.500.730.437.340.171.838.891.251.943.028.869.039.612.929.246.368.535.415.502.947.874.821.
717        {
718            let cell: Noun = Noun::from(Cell::from([
719                Noun::from(Cell::from(["x-cached", "HIT"])),
720                Noun::from(Cell::from(["vary", "Origin"])),
721                Noun::from(Cell::from(["vary", "Accept-Encoding"])),
722                Noun::from(Cell::from(["connection", "keep-alive"])),
723                Noun::from(Cell::from(["content-length", "59"])),
724                Noun::from(Cell::from(["content-type", "application/json"])),
725                Noun::from(Cell::from(["date", "Fri, 08 Jul 2022 16:43:50 GMT"])),
726                Noun::from(Cell::from(["server", "nginx/1.14.0 (Ubuntu)"])),
727                Noun::from(Atom::from(0u8)),
728            ]));
729            let jammed_cell = Atom::from(vec![
730                5, 248, 241, 90, 198, 194, 198, 208, 202, 200, 192, 67, 74, 162, 22, 240, 237, 194,
731                228, 242, 128, 239, 73, 46, 237, 44, 205, 93, 227, 118, 128, 119, 208, 216, 88, 25,
732                28, 93, 75, 145, 219, 216, 27, 89, 154, 219, 185, 0, 62, 99, 111, 110, 110, 101,
733                99, 116, 105, 111, 110, 128, 207, 90, 89, 25, 92, 75, 24, 91, 154, 93, 185, 0, 190,
734                99, 111, 110, 116, 101, 110, 116, 45, 108, 101, 110, 103, 116, 104, 208, 53, 121,
735                1, 252, 198, 222, 220, 232, 202, 220, 232, 90, 232, 242, 224, 202, 0, 255, 48, 56,
736                56, 182, 180, 177, 48, 186, 180, 55, 183, 23, 181, 185, 55, 119, 1, 159, 44, 140,
737                174, 12, 224, 217, 72, 46, 141, 5, 4, 6, 7, 68, 169, 142, 13, 68, 6, 70, 70, 6, 36,
738                198, 70, 135, 102, 70, 167, 6, 6, 228, 168, 137, 90, 128, 111, 174, 76, 206, 174,
739                76, 14, 160, 201, 237, 44, 205, 13, 239, 37, 198, 37, 134, 198, 5, 6, 4, 165, 74,
740                172, 206, 141, 174, 46, 21,
741            ]);
742            assert_eq!(cell.clone().clone().jam(), jammed_cell);
743            assert_eq!(Noun::cue(jammed_cell).expect("cue"), cell);
744        }
745
746        // [
747        //  %request
748        //  0
749        //  'POST'
750        //  'http://eth-mainnet.urbit.org:8545'
751        //  [['Content-Type' 'application/json'] 0]
752        //  0
753        //  78
754        //  '[{"params":[],"id":"block number","jsonrpc":"2.0","method":"eth_blockNumber"}]'
755        // ]
756        // serializes to
757        // 534.926.240.328.183.504.043.224.467.158.150.263.359.506.153.835.684.400.054.708.654.784.265.586.779.466.767.311.401.093.568.872.399.514.089.871.794.788.465.339.360.316.141.009.784.521.401.502.584.590.628.538.383.397.474.667.076.686.296.931.914.112.162.585.777.490.924.604.432.397.967.740.482.953.038.069.595.525.949.395.091.512.693.509.388.265.834.094.423.223.982.487.236.123.144.939.682.105.684.811.115.401.159.600.617.316.591.045.520.893.570.145.126.936.115.415.644.005.172.954.075.003.434.319.780.206.191.080.707.020.476.210.689.
758        //
759        // 534926240328183504043224467158150263359506153835684400054708654784265586779466767311401093568872399514089871794788465339360316141009784521401502584590628538383397474667076686296931914112162585777490924604432397967740482953038069595525949395091512693509388265834094423223982487236123144939682105684811115401159600617316591045520893570145126936115415644005172954075003434319780206191080707020476210689
760        {
761            let cell: Noun = Noun::from(Cell::from([
762                Noun::from(Atom::from("request")),
763                Noun::from(Atom::from(0u8)),
764                Noun::from(Atom::from("POST")),
765                Noun::from(Atom::from("http://eth-mainnet.urbit.org:8545")),
766                Noun::from(Cell::from([
767                    Noun::from(Cell::from([
768                        Atom::from("Content-Type"),
769                        Atom::from("application/json"),
770                    ])),
771                    Noun::from(Atom::from(0u8)),
772                ])),
773                Noun::from(Atom::from(0u8)),
774                Noun::from(Atom::from(78u8)),
775                Noun::from(Atom::from(
776                    r#"[{"params":[],"id":"block number","jsonrpc":"2.0","method":"eth_blockNumber"}]"#,
777                )),
778            ]));
779            let jammed_cell = Atom::from(vec![
780                1, 94, 185, 178, 184, 186, 178, 57, 122, 6, 124, 168, 167, 41, 106, 0, 52, 64, 163,
781                163, 131, 211, 121, 121, 41, 163, 67, 107, 105, 11, 75, 115, 115, 43, 163, 115,
782                169, 147, 19, 75, 163, 115, 121, 147, 59, 211, 193, 169, 161, 169, 43, 128, 223,
783                208, 155, 27, 93, 153, 27, 93, 11, 85, 30, 92, 25, 224, 31, 6, 7, 199, 150, 54, 22,
784                70, 151, 246, 230, 246, 162, 54, 247, 230, 54, 131, 59, 1, 240, 205, 214, 158, 8,
785                92, 152, 92, 88, 219, 156, 136, 206, 86, 23, 139, 72, 26, 153, 136, 142, 136, 24,
786                219, 219, 216, 26, 136, 91, 93, 155, 88, 153, 156, 8, 139, 136, 218, 220, 155, 155,
787                28, 220, 152, 136, 142, 136, 140, 11, 140, 8, 139, 72, 91, 25, 29, 218, 27, 153,
788                136, 142, 72, 25, 29, 218, 151, 24, 219, 219, 216, 154, 83, 93, 155, 88, 153, 156,
789                72, 95, 23,
790            ]);
791            assert_eq!(cell.clone().clone().jam(), jammed_cell);
792            assert_eq!(Noun::cue(jammed_cell).expect("cue"), cell);
793        }
794    }
795}