on master help sign in
memo
862a57diko
nock/one.hoon+1−1
@@ -1 +1 @@
1−=> ~ |=(@ 'Hello')
1+=> ~ ~+ |=(@ 'Hello')
nock/one.nock+1−1
@@ -1 +1 @@
1−���� �����
1+�d �mem���pq x������
nock/src/interpreter.rs+63−44
@@ -1,4 +1,5 @@
1use std::borrow::Borrow;
1use std::borrow::Borrow;
2+use std::collections::BTreeMap;
2use std::rc::Rc;
3use std::rc::Rc;
3
4
4use num_bigint::BigUint;
5use num_bigint::BigUint;
@@ -16,6 +17,7 @@ pub struct Nouns {
16 pub four: Rc<Noun>,
17 pub four: Rc<Noun>,
17 pub sig_one: Rc<Noun>,
18 pub sig_one: Rc<Noun>,
18 pub two_three: Rc<Noun>,
19 pub two_three: Rc<Noun>,
20+ pub memo: Rc<Noun>,
19}
21}
20
22
21pub struct BigUints {
23pub struct BigUints {
@@ -31,6 +33,7 @@ pub struct InterpreterContext {
31 pub double_jets: DoubleJets,
33 pub double_jets: DoubleJets,
32 pub nouns: Nouns,
34 pub nouns: Nouns,
33 pub big_uints: BigUints,
35 pub big_uints: BigUints,
36+ pub memo: BTreeMap<Hash, Rc<Noun>>,
34}
37}
35
38
36pub fn generate_interpreter_context() -> InterpreterContext {
39pub fn generate_interpreter_context() -> InterpreterContext {
@@ -50,6 +53,7 @@ pub fn generate_interpreter_context() -> InterpreterContext {
50 let four = Rc::new(Noun::Atom(big_uints.four.clone()));
53 let four = Rc::new(Noun::Atom(big_uints.four.clone()));
51 let sig_one = cell(&sig, &one);
54 let sig_one = cell(&sig, &one);
52 let two_three = cell(&two, &three);
55 let two_three = cell(&two, &three);
56+ let memo = Rc::new(Noun::from_bytes(b"memo"));
53 InterpreterContext {
57 InterpreterContext {
54 jets,
58 jets,
55 double_jets,
59 double_jets,
@@ -63,8 +67,10 @@ pub fn generate_interpreter_context() -> InterpreterContext {
63 four,
67 four,
64 sig_one,
68 sig_one,
65 two_three,
69 two_three,
70+ memo,
66 },
71 },
67 big_uints,
72 big_uints,
73+ memo: BTreeMap::new(),
68 }
74 }
69}
75}
70
76
@@ -172,15 +178,15 @@ fn hax(
172}
178}
173
179
174fn tar_u32<'a>(
180fn tar_u32<'a>(
175− ctx: &InterpreterContext,
181+ ctx: &mut InterpreterContext,
176− subj: &'a Noun,
182+ subj: Rc<Noun>,
177 op: u32,
183 op: u32,
178 formula: &'a Rc<Noun>,
184 formula: &'a Rc<Noun>,
179) -> Option<Rc<Noun>> {
185) -> Option<Rc<Noun>> {
180 match op {
186 match op {
181 0 => {
187 0 => {
182 let b = formula.as_atom()?;
188 let b = formula.as_atom()?;
183− fas(ctx, b, subj)
189+ fas(ctx, b, &*subj)
184 }
190 }
185 1 => Some(formula.clone()),
191 1 => Some(formula.clone()),
186 2 => {
192 2 => {
@@ -196,16 +202,16 @@ fn tar_u32<'a>(
196 match ctx.jets.get(&hash) {
202 match ctx.jets.get(&hash) {
197 Some(f) => f(ctx, sample),
203 Some(f) => f(ctx, sample),
198 None => {
204 None => {
199− let foo = tar(ctx, subj, &b)?;
205+ let foo = tar(ctx, subj.clone(), &b)?;
200 let bar = tar(ctx, subj, &c)?;
206 let bar = tar(ctx, subj, &c)?;
201− tar(ctx, &foo, &bar)
207+ tar(ctx, foo, &bar)
202 }
208 }
203 }
209 }
204 }
210 }
205 _ => {
211 _ => {
206− let foo = tar(ctx, &subj, &b)?;
212+ let foo = tar(ctx, subj.clone(), &b)?;
207− let bar = tar(ctx, &subj, &c)?;
213+ let bar = tar(ctx, subj, &c)?;
208− tar(ctx, &foo, &bar)
214+ tar(ctx, foo, &bar)
209 }
215 }
210 }
216 }
211 }
217 }
@@ -219,7 +225,7 @@ fn tar_u32<'a>(
219 }
225 }
220 5 => {
226 5 => {
221 let (b, c) = formula.as_cell()?;
227 let (b, c) = formula.as_cell()?;
222− let foo = tar(ctx, &subj, &b)?;
228+ let foo = tar(ctx, subj.clone(), &b)?;
223 let bar = tar(ctx, subj, &c)?;
229 let bar = tar(ctx, subj, &c)?;
224 Some(tis(ctx, &foo, &bar).clone())
230 Some(tis(ctx, &foo, &bar).clone())
225 }
231 }
@@ -227,36 +233,29 @@ fn tar_u32<'a>(
227 let (b, c) = formula.as_cell()?;
233 let (b, c) = formula.as_cell()?;
228 let (c, d) = c.as_cell()?;
234 let (c, d) = c.as_cell()?;
229
235
230− let foo = tar_u32(
231− ctx,
232− &cell(&c, &d),
233− 0,
234− &tar_u32(
235− ctx,
236− &ctx.nouns.two_three,
237− 0,
238− &tar_u32(ctx, subj, 4, &cell(&ctx.nouns.four, &b))?,
236+ let bar = tar_u32(ctx, subj.clone(), 4, &cell(&ctx.nouns.four.clone(), &b))?;
239− )?,
240− )?;
241
237
238+ let foo = tar_u32(ctx, ctx.nouns.two_three.clone(), 0, &bar)?;
239+ let foo = tar_u32(ctx, cell(&c, &d), 0, &foo)?;
240+
242− tar(ctx, &subj, &foo)
241+ tar(ctx, subj, &foo)
243 }
242 }
244 7 => {
243 7 => {
245 let (b, c) = formula.as_cell()?;
244 let (b, c) = formula.as_cell()?;
246 let foo = tar(ctx, subj, &b)?;
245 let foo = tar(ctx, subj, &b)?;
247− tar(ctx, &foo, &c)
246+ tar(ctx, foo, &c)
248 }
247 }
249 8 => {
248 8 => {
250 let (b, c) = formula.as_cell()?;
249 let (b, c) = formula.as_cell()?;
251− let foo = tar(ctx, &subj, &b)?;
250+ let foo = tar(ctx, subj.clone(), &b)?;
252− tar(ctx, &cell(&foo, &Rc::new(subj.clone())), &c)
251+ tar(ctx, cell(&foo, &subj), &c)
253 }
252 }
254 9 => {
253 9 => {
255 let (b, c) = formula.as_cell()?;
254 let (b, c) = formula.as_cell()?;
256− let foo = tar(ctx, &subj, &c)?;
255+ let foo = tar(ctx, subj, &c)?;
257 tar_u32(
256 tar_u32(
258 ctx,
257 ctx,
259− &foo,
258+ foo,
260 2,
259 2,
261 &cell(&ctx.nouns.sig_one, &cell(&ctx.nouns.sig, &b)),
260 &cell(&ctx.nouns.sig_one, &cell(&ctx.nouns.sig, &b)),
262 )
261 )
@@ -266,17 +265,33 @@ fn tar_u32<'a>(
266 let (b, c) = b.as_cell()?;
265 let (b, c) = b.as_cell()?;
267 let b = b.as_atom()?;
266 let b = b.as_atom()?;
268
267
268+ let foo = tar(ctx, subj.clone(), &c)?;
269− hax(ctx, b, &tar(ctx, subj, &c)?, &tar(ctx, subj, &d)?)
269+ let bar = tar(ctx, subj, &d)?;
270+ hax(ctx, b, &foo, &bar)
270 }
271 }
271 11 => {
272 11 => {
272 let (b, d) = formula.as_cell()?;
273 let (b, d) = formula.as_cell()?;
273− // println!("{b}");
274 match b.borrow() {
274 match b.borrow() {
275 Noun::Atom(_) => tar(ctx, subj, &d),
275 Noun::Atom(_) => tar(ctx, subj, &d),
276− Noun::Cell { q: c, .. } => {
276+ Noun::Cell { p, q, .. } => {
277+ if *p == ctx.nouns.memo {
278+ let hash = cell(&subj, formula).hash();
279+ match ctx.memo.get(&hash) {
280+ Some(target) => Some(target.clone()),
281+ None => {
282+ let foo = cell(
283+ &tar(ctx, subj.clone(), &q)?,
277− let foo = tar(ctx, subj, &c)?;
284+ &tar(ctx, subj.clone(), &d)?,
278− let bar = tar(ctx, subj, &d)?;
285+ );
286+ let target = tar_u32(ctx, foo, 0, &ctx.nouns.three.clone())?;
287+ ctx.memo.insert(hash, target.clone());
288+ Some(target)
289+ }
290+ }
291+ } else {
292+ let foo = cell(&tar(ctx, subj.clone(), &q)?, &tar(ctx, subj.clone(), &d)?);
279− tar_u32(ctx, &cell(&foo, &bar), 0, &ctx.nouns.three)
293+ tar_u32(ctx, foo, 0, &ctx.nouns.three.clone())
294+ }
280 }
295 }
281 }
296 }
282 }
297 }
@@ -284,11 +299,15 @@ fn tar_u32<'a>(
284 }
299 }
285}
300}
286
301
302+pub fn tar<'a>(
287−pub fn tar<'a>(ctx: &InterpreterContext, subj: &'a Noun, formula: &'a Noun) -> Option<Rc<Noun>> {
303+ ctx: &mut InterpreterContext,
304+ subj: Rc<Noun>,
305+ formula: &'a Noun,
306+) -> Option<Rc<Noun>> {
288 let (op, formula) = formula.as_cell()?;
307 let (op, formula) = formula.as_cell()?;
289 match op.borrow() {
308 match op.borrow() {
290 Noun::Cell { .. } => {
309 Noun::Cell { .. } => {
291− let foo = tar(ctx, subj, &op)?;
310+ let foo = tar(ctx, subj.clone(), &op)?;
292 let bar = tar(ctx, subj, &formula)?;
311 let bar = tar(ctx, subj, &formula)?;
293 Some(cell(&foo, &bar))
312 Some(cell(&foo, &bar))
294 }
313 }
@@ -305,27 +324,27 @@ pub fn tar<'a>(ctx: &InterpreterContext, subj: &'a Noun, formula: &'a Noun) -> O
305 }
324 }
306}
325}
307
326
308−pub fn eval_gate(ctx: &InterpreterContext, gate_factory: &Rc<Noun>) -> Option<Rc<Noun>> {
327+pub fn eval_gate(ctx: &mut InterpreterContext, gate_factory: &Rc<Noun>) -> Option<Rc<Noun>> {
309− let pulled_gate = tar(ctx, &ctx.nouns.sig, &gate_factory)?;
328+ let pulled_gate = tar(ctx, ctx.nouns.sig.clone(), &gate_factory)?;
310− eval_pulled_gate(ctx, &pulled_gate)
329+ eval_pulled_gate(ctx, pulled_gate)
311}
330}
312
331
313pub fn slam(
332pub fn slam(
314− ctx: &InterpreterContext,
333+ ctx: &mut InterpreterContext,
315 gate_factory: &Rc<Noun>,
334 gate_factory: &Rc<Noun>,
316 sample: &Rc<Noun>,
335 sample: &Rc<Noun>,
317) -> Option<Rc<Noun>> {
336) -> Option<Rc<Noun>> {
318− let gate = tar(ctx, &ctx.nouns.sig, &gate_factory)?;
337+ let gate = tar(ctx, ctx.nouns.sig.clone(), &gate_factory)?;
319
338
320− eval_pulled_gate(ctx, &replace_sample(&gate, sample)?)
339+ eval_pulled_gate(ctx, replace_sample(&gate, sample)?)
321}
340}
322
341
323/// This is useful for evaluaing gates produced by running `.foo/nock gate-name` in the dojo.
342/// This is useful for evaluaing gates produced by running `.foo/nock gate-name` in the dojo.
324/// Also for calling gates from within jets.
343/// Also for calling gates from within jets.
325−pub fn eval_pulled_gate(ctx: &InterpreterContext, gate: &Rc<Noun>) -> Option<Rc<Noun>> {
344+pub fn eval_pulled_gate(ctx: &mut InterpreterContext, gate: Rc<Noun>) -> Option<Rc<Noun>> {
326 tar(
345 tar(
327 ctx,
346 ctx,
328− &gate,
347+ gate,
329 &cell(
348 &cell(
330 &Rc::new(Noun::Atom(BigUint::new(vec![9]))),
349 &Rc::new(Noun::Atom(BigUint::new(vec![9]))),
331 &cell(&ctx.nouns.two, &cell(&ctx.nouns.sig, &ctx.nouns.one)),
350 &cell(&ctx.nouns.two, &cell(&ctx.nouns.sig, &ctx.nouns.one)),
@@ -336,11 +355,11 @@ pub fn eval_pulled_gate(ctx: &InterpreterContext, gate: &Rc<Noun>) -> Option<Rc<
336/// This is useful for evaluaing gates produced by running `.foo/nock gate-name` in the dojo.
355/// This is useful for evaluaing gates produced by running `.foo/nock gate-name` in the dojo.
337/// Also for calling gates from within jets.
356/// Also for calling gates from within jets.
338pub fn slam_pulled_gate(
357pub fn slam_pulled_gate(
339− ctx: &InterpreterContext,
358+ ctx: &mut InterpreterContext,
340 gate: &Rc<Noun>,
359 gate: &Rc<Noun>,
341 sample: &Rc<Noun>,
360 sample: &Rc<Noun>,
342) -> Option<Rc<Noun>> {
361) -> Option<Rc<Noun>> {
343− eval_pulled_gate(ctx, &replace_sample(gate, sample)?)
362+ eval_pulled_gate(ctx, replace_sample(gate, sample)?)
344}
363}
345
364
346pub fn replace_sample(gate: &Rc<Noun>, sample: &Rc<Noun>) -> Option<Rc<Noun>> {
365pub fn replace_sample(gate: &Rc<Noun>, sample: &Rc<Noun>) -> Option<Rc<Noun>> {
nock/src/jets.rs+37−13
@@ -8,7 +8,7 @@ use std::{
8};
8};
9
9
10use crate::{
10use crate::{
11− interpreter::{slam, slam_pulled_gate, InterpreterContext},
11+ interpreter::{slam_pulled_gate, InterpreterContext},
12 noun::{self, cell, Atom, Edge, Hair, Nail, Noun},
12 noun::{self, cell, Atom, Edge, Hair, Nail, Noun},
13};
13};
14
14
@@ -104,11 +104,12 @@ pub fn generate_jets() -> Jets {
104 (3482046397915506566435874021936376320, LAST),
104 (3482046397915506566435874021936376320, LAST),
105 (124976064672625230427889101290245200507, TRIP),
105 (124976064672625230427889101290245200507, TRIP),
106 (4078279288073906183633157465551067635, MUK),
106 (4078279288073906183633157465551067635, MUK),
107+ (261900159748071234702685239353558471892, MUG),
107 ])
108 ])
108}
109}
109
110
110−pub type Jet = fn(ctx: &InterpreterContext, &Rc<Noun>) -> Option<Rc<Noun>>;
111+pub type Jet = fn(ctx: &mut InterpreterContext, &Rc<Noun>) -> Option<Rc<Noun>>;
111−pub type DoubleJet = fn(ctx: &InterpreterContext, &Rc<Noun>, &Rc<Noun>) -> Option<Rc<Noun>>;
112+pub type DoubleJet = fn(ctx: &mut InterpreterContext, &Rc<Noun>, &Rc<Noun>) -> Option<Rc<Noun>>;
112
113
113static BINARY_ATOM: fn(&Rc<Noun>, fn(&Atom, &Atom) -> Atom) -> Option<Rc<Noun>> =
114static BINARY_ATOM: fn(&Rc<Noun>, fn(&Atom, &Atom) -> Atom) -> Option<Rc<Noun>> =
114 |n: &Rc<Noun>, f: fn(&Atom, &Atom) -> Atom| {
115 |n: &Rc<Noun>, f: fn(&Atom, &Atom) -> Atom| {
@@ -941,16 +942,7 @@ static MUK: Jet = |_ctx, n| {
941 let len = len.as_u32()?;
942 let len = len.as_u32()?;
942 let key = key.as_atom()?;
943 let key = key.as_atom()?;
943
944
944− let key: Vec<_> = key
945− .to_bytes_le()
946− .iter()
947− .take(len as usize)
948− .cloned()
949− .collect();
950−
951− Some(Rc::new(Noun::from_u32(
945+ Some(Rc::new(Noun::from_u32(muk(seed, len, key))))
952− murmur3_32(&mut &*key, seed).unwrap(),
953− )))
954};
946};
955
947
956static JUST: DoubleJet = |ctx, n, m| {
948static JUST: DoubleJet = |ctx, n, m| {
@@ -1013,3 +1005,35 @@ fn fail(nail: Nail) -> Edge {
1013 result: None,
1005 result: None,
1014 }
1006 }
1015}
1007}
1008+
1009+const MUG: Jet = |__ctx, n| Some(Rc::new(Noun::from_u32(n.mug())));
1010+
1011+pub fn mum(syd: u32, fal: u32, key: &Atom) -> u32 {
1012+ let wyd = met(3, &key);
1013+ let mut i = 0;
1014+ loop {
1015+ if i == 8 {
1016+ break fal;
1017+ } else {
1018+ let haz = muk(syd, wyd, &key);
1019+ let ham = (haz >> 31) ^ (haz & !(1 << 31));
1020+ if ham == 0 {
1021+ i += 1;
1022+ continue;
1023+ } else {
1024+ break ham;
1025+ }
1026+ }
1027+ }
1028+}
1029+
1030+fn muk(seed: u32, len: u32, key: &Atom) -> u32 {
1031+ let key: Vec<_> = key
1032+ .to_bytes_le()
1033+ .iter()
1034+ .take(len as usize)
1035+ .cloned()
1036+ .collect();
1037+
1038+ murmur3_32(&mut &*key, seed).unwrap()
1039+}
nock/src/main.rs+7−7
@@ -1,5 +1,5 @@
1use clap::{command, error::Result, Parser, Subcommand};
1use clap::{command, error::Result, Parser, Subcommand};
2−use nock::interpreter::{eval_gate, eval_pulled_gate, slam_pulled_gate};
2+use nock::interpreter::{eval_pulled_gate, slam_pulled_gate};
3use nock::{
3use nock::{
4 cue::cue_bytes,
4 cue::cue_bytes,
5 interpreter::{generate_interpreter_context, slam},
5 interpreter::{generate_interpreter_context, slam},
@@ -90,15 +90,15 @@ fn main() -> Result<(), std::io::Error> {
90 NockCommand::EvalGate { gate } => {
90 NockCommand::EvalGate { gate } => {
91 let gate = read_nock(&gate).unwrap();
91 let gate = read_nock(&gate).unwrap();
92
92
93− let result = eval_pulled_gate(&generate_interpreter_context(), &gate).unwrap();
93+ let result = eval_pulled_gate(&mut generate_interpreter_context(), gate).unwrap();
94
94
95 println!("{result}");
95 println!("{result}");
96 }
96 }
97 NockCommand::Eval { nock } => {
97 NockCommand::Eval { nock } => {
98 let nock = read_nock(&nock).unwrap();
98 let nock = read_nock(&nock).unwrap();
99
99
100− let ctx = generate_interpreter_context();
100+ let mut ctx = generate_interpreter_context();
101− let result = eval_pulled_gate(&ctx, &nock).unwrap();
101+ let result = eval_pulled_gate(&mut ctx, nock).unwrap();
102
102
103 println!("{result}");
103 println!("{result}");
104 }
104 }
@@ -118,7 +118,7 @@ fn interact(gate_file: PathBuf) -> Result<(), std::io::Error> {
118 let source = get_stdin().unwrap();
118 let source = get_stdin().unwrap();
119
119
120 let mut spinner = new_spinner(String::from("Slamming gate..."));
120 let mut spinner = new_spinner(String::from("Slamming gate..."));
121− let Some(slam) = slam(&generate_interpreter_context(), &gate, &source) else {
121+ let Some(slam) = slam(&mut generate_interpreter_context(), &gate, &source) else {
122 spinner.fail("Gate execution failed");
122 spinner.fail("Gate execution failed");
123 exit(1);
123 exit(1);
124 };
124 };
@@ -163,7 +163,7 @@ fn compile(root: PathBuf, output: PathBuf) -> Result<(), std::io::Error> {
163 let root_source = read_file(&root)?;
163 let root_source = read_file(&root)?;
164
164
165 slam_pulled_gate(
165 slam_pulled_gate(
166− &generate_interpreter_context(),
166+ &mut generate_interpreter_context(),
167 &ream_gate,
167 &ream_gate,
168 &Rc::new(Noun::Atom(Atom::from_bytes_le(&root_source))),
168 &Rc::new(Noun::Atom(Atom::from_bytes_le(&root_source))),
169 )
169 )
@@ -185,7 +185,7 @@ fn compile(root: PathBuf, output: PathBuf) -> Result<(), std::io::Error> {
185
185
186 let mint_gate = cue_bytes(include_bytes!("../res/mint.nock"));
186 let mint_gate = cue_bytes(include_bytes!("../res/mint.nock"));
187 let minted_ast =
187 let minted_ast =
188− slam_pulled_gate(&generate_interpreter_context(), &mint_gate, &root_ast).unwrap();
188+ slam_pulled_gate(&mut generate_interpreter_context(), &mint_gate, &ast).unwrap();
189 let (_type, nock) = minted_ast.as_cell().unwrap();
189 let (_type, nock) = minted_ast.as_cell().unwrap();
190
190
191 let mut output_file = File::create(output)?;
191 let mut output_file = File::create(output)?;
nock/src/noun.rs+24−3
@@ -4,9 +4,12 @@ use num_bigint::BigUint;
4use std::fmt;
4use std::fmt;
5use xxhash_rust::xxh3::xxh3_128;
5use xxhash_rust::xxh3::xxh3_128;
6
6
7+use crate::jets::mum;
8+
7pub type Atom = BigUint;
9pub type Atom = BigUint;
8
10
9pub type Hash = u128;
11pub type Hash = u128;
12+pub type Mug = u32;
10
13
11#[derive(Clone, Debug, Eq)]
14#[derive(Clone, Debug, Eq)]
12pub enum Noun {
15pub enum Noun {
@@ -15,6 +18,7 @@ pub enum Noun {
15 p: Rc<Noun>,
18 p: Rc<Noun>,
16 q: Rc<Noun>,
19 q: Rc<Noun>,
17 hash: Cell<Option<Hash>>,
20 hash: Cell<Option<Hash>>,
21+ mug: Cell<Option<Mug>>,
18 },
22 },
19}
23}
20
24
@@ -126,8 +130,8 @@ impl<'a> Noun {
126
130
127 pub fn hash(self: &Self) -> Hash {
131 pub fn hash(self: &Self) -> Hash {
128 match self {
132 match self {
129− Noun::Cell { hash, p, q } => match hash.get() {
133+ Noun::Cell { hash, p, q, .. } => match hash.get() {
130− Some(x) => x.clone(),
134+ Some(x) => x,
131 None => {
135 None => {
132 let hash_value =
136 let hash_value =
133 stacker::maybe_grow(32 * 1024, 1024 * 1024, || hash_pair(p, q));
137 stacker::maybe_grow(32 * 1024, 1024 * 1024, || hash_pair(p, q));
@@ -139,6 +143,22 @@ impl<'a> Noun {
139 }
143 }
140 }
144 }
141
145
146+ pub fn mug(self: &Self) -> Mug {
147+ match self {
148+ Noun::Cell { mug, p, q, .. } => match mug.get() {
149+ Some(x) => x,
150+ None => {
151+ let mug_value = stacker::maybe_grow(32 * 1024, 1024 * 1024, || {
152+ mum(0xDEADBEEF, 0xFFFE, &Atom::new(vec![p.mug(), q.mug()]))
153+ });
154+ mug.replace(Some(mug_value));
155+ mug_value
156+ }
157+ },
158+ Self::Atom(a) => mum(0xCAFEBABE, 0x7FFF, a),
159+ }
160+ }
161+
142 /// returns the hash and the current sample
162 /// returns the hash and the current sample
143 pub fn hash_gate(self: &Self) -> (Hash, &Rc<Noun>) {
163 pub fn hash_gate(self: &Self) -> (Hash, &Rc<Noun>) {
144 let (battery, payload) = self.as_cell().unwrap();
164 let (battery, payload) = self.as_cell().unwrap();
@@ -323,7 +343,7 @@ fn write_noun(f: &mut fmt::Formatter, noun: &Noun, is_rhs: bool) -> fmt::Result
323 }
343 }
324 Noun::Atom(a) => {
344 Noun::Atom(a) => {
325 let atom_bytes = a.to_bytes_le();
345 let atom_bytes = a.to_bytes_le();
326− if atom_bytes.len() > 1 && atom_bytes.into_iter().all(|c| (c > 33) && c < 126) {
346+ if atom_bytes.len() > 0 && atom_bytes.into_iter().all(|c| (c > 33) && c < 126) {
327 f.write_char('%')?;
347 f.write_char('%')?;
328 let cord = unsafe { String::from_utf8_unchecked(a.to_bytes_le()) };
348 let cord = unsafe { String::from_utf8_unchecked(a.to_bytes_le()) };
329 f.write_str(&*cord)
349 f.write_str(&*cord)
@@ -355,6 +375,7 @@ pub fn naked_cell(p: &Rc<Noun>, q: &Rc<Noun>) -> Noun {
355 p: p.clone(),
375 p: p.clone(),
356 q: q.clone(),
376 q: q.clone(),
357 hash: Cell::new(None),
377 hash: Cell::new(None),
378+ mug: Cell::new(None),
358 }
379 }
359}
380}
360
381