1use std::collections::HashMap;
34use std::fmt;
35use std::hash::{BuildHasherDefault, Hasher};
36
37use bumpalo::Bump;
38
39use crate::borrowed::{MapRef, ValueRef};
40use crate::value::{Map, Ref, Res, Value};
41
42pub const MAGIC: &[u8; 4] = b"YOGD";
43pub const VERSION: u8 = 1;
44
45pub const MAX_DEPTH: usize = 256;
47
48mod tag {
49 pub const NULL: u8 = 0;
50 pub const FALSE: u8 = 1;
51 pub const TRUE: u8 = 2;
52 pub const INT: u8 = 3;
53 pub const FLOAT: u8 = 4;
54 pub const STR: u8 = 5;
55 pub const LIST: u8 = 6;
56 pub const MAP: u8 = 7;
57 pub const REF: u8 = 8;
58 pub const TAG: u8 = 9;
59 pub const RES: u8 = 10;
60 pub const TEXT: u8 = 11;
61 pub const IMAGE: u8 = 12;
62 pub const COLOR: u8 = 13;
63 pub const LANG: u8 = 14;
64}
65
66pub fn encode(value: &Value) -> Vec<u8> {
68 let mut w = Writer::new();
69 w.value(value);
70 w.finish()
71}
72
73pub struct Writer<'v>(Encoder<'v>);
85
86impl Default for Writer<'_> {
87 fn default() -> Self {
88 Self::new()
89 }
90}
91
92impl<'v> Writer<'v> {
93 pub fn new() -> Self {
94 Writer(Encoder { body: Vec::new(), strings: HashMap::default(), table: Vec::new() })
95 }
96
97 pub fn null(&mut self) -> &mut Self {
98 self.0.body.push(tag::NULL);
99 self
100 }
101
102 pub fn bool(&mut self, b: bool) -> &mut Self {
103 self.0.body.push(if b { tag::TRUE } else { tag::FALSE });
104 self
105 }
106
107 pub fn int(&mut self, n: i64) -> &mut Self {
108 self.0.body.push(tag::INT);
109 varint(&mut self.0.body, ((n << 1) ^ (n >> 63)) as u64);
110 self
111 }
112
113 pub fn float(&mut self, f: f64) -> &mut Self {
114 self.0.body.push(tag::FLOAT);
115 self.0.body.extend_from_slice(&f.to_le_bytes());
116 self
117 }
118
119 pub fn str(&mut self, s: &'v str) -> &mut Self {
120 self.0.body.push(tag::STR);
121 self.0.string(s);
122 self
123 }
124
125 pub fn list(&mut self, len: usize) -> &mut Self {
127 self.0.body.push(tag::LIST);
128 varint(&mut self.0.body, len as u64);
129 self
130 }
131
132 pub fn map(&mut self, len: usize) -> &mut Self {
134 self.0.body.push(tag::MAP);
135 varint(&mut self.0.body, len as u64);
136 self
137 }
138
139 pub fn key(&mut self, k: &'v str) -> &mut Self {
140 self.0.string(k);
141 self
142 }
143
144 pub fn value(&mut self, v: &'v Value) -> &mut Self {
145 self.0.value(v);
146 self
147 }
148
149 pub fn finish(self) -> Vec<u8> {
151 let enc = self.0;
152 let table_len: usize = enc.table.iter().map(|s| s.len() + 2).sum();
153 let mut out = Vec::with_capacity(5 + table_len + enc.body.len() + 4);
154 out.extend_from_slice(MAGIC);
155 out.push(VERSION);
156 varint(&mut out, enc.table.len() as u64);
157 for s in &enc.table {
158 varint(&mut out, s.len() as u64);
159 out.extend_from_slice(s.as_bytes());
160 }
161 out.extend_from_slice(&enc.body);
162 out
163 }
164}
165
166struct Encoder<'v> {
167 body: Vec<u8>,
168 strings: HashMap<&'v str, u32, BuildHasherDefault<Fx>>,
169 table: Vec<&'v str>,
170}
171
172impl<'v> Encoder<'v> {
173 fn string(&mut self, s: &'v str) {
174 let next = self.table.len() as u32;
175 let i = *self.strings.entry(s).or_insert_with(|| {
176 self.table.push(s);
177 next
178 });
179 varint(&mut self.body, i as u64);
180 }
181
182 fn value(&mut self, v: &'v Value) {
183 match v {
184 Value::Null => self.body.push(tag::NULL),
185 Value::Bool(false) => self.body.push(tag::FALSE),
186 Value::Bool(true) => self.body.push(tag::TRUE),
187 Value::Int(n) => {
188 self.body.push(tag::INT);
189 varint(&mut self.body, ((n << 1) ^ (n >> 63)) as u64);
190 }
191 Value::Float(f) => {
192 self.body.push(tag::FLOAT);
193 self.body.extend_from_slice(&f.to_le_bytes());
194 }
195 Value::Str(s) => {
196 self.body.push(tag::STR);
197 self.string(s);
198 }
199 Value::List(items) => {
200 self.body.push(tag::LIST);
201 varint(&mut self.body, items.len() as u64);
202 for item in items {
203 self.value(item);
204 }
205 }
206 Value::Map(map) => {
207 self.body.push(tag::MAP);
208 varint(&mut self.body, map.len() as u64);
209 for (k, v) in map.iter() {
210 self.string(k);
211 self.value(v);
212 }
213 }
214 Value::Ref(r) | Value::Tag(r) => {
215 self.body.push(if matches!(v, Value::Ref(_)) {
216 tag::REF
217 } else {
218 tag::TAG
219 });
220 self.string(&r.kind);
221 self.string(&r.id);
222 }
223 Value::Res(r) => {
224 self.body.push(tag::RES);
225 self.string(&r.set);
226 self.string(&r.key);
227 }
228 Value::Text(s) => {
229 self.body.push(tag::TEXT);
230 self.string(s);
231 }
232 Value::Image(s) => {
233 self.body.push(tag::IMAGE);
234 self.string(s);
235 }
236 Value::Lang(s) => {
237 self.body.push(tag::LANG);
238 self.string(s);
239 }
240 Value::Color(c) => {
241 self.body.push(tag::COLOR);
242 self.body.extend_from_slice(&c.to_le_bytes());
243 }
244 }
245 }
246}
247
248#[derive(Default)]
250struct Fx(u64);
251
252impl Fx {
253 fn add(&mut self, word: u64) {
254 self.0 = (self.0.rotate_left(5) ^ word).wrapping_mul(0x51_7c_c1_b7_27_22_0a_95);
255 }
256}
257
258impl Hasher for Fx {
259 fn write(&mut self, bytes: &[u8]) {
260 let (words, rest) = bytes.as_chunks::<8>();
261 for w in words {
262 self.add(u64::from_le_bytes(*w));
263 }
264 if !rest.is_empty() {
265 let mut b = [0u8; 8];
266 b[..rest.len()].copy_from_slice(rest);
267 self.add(u64::from_le_bytes(b));
268 }
269 }
270
271 fn write_u8(&mut self, b: u8) {
272 self.add(b as u64);
273 }
274
275 fn finish(&self) -> u64 {
276 self.0
277 }
278}
279
280fn varint(out: &mut Vec<u8>, mut n: u64) {
281 while n >= 0x80 {
282 out.push((n as u8) | 0x80);
283 n >>= 7;
284 }
285 out.push(n as u8);
286}
287
288#[derive(Debug, Clone, PartialEq, Eq)]
290pub struct DecodeError {
291 pub message: String,
292 pub offset: usize,
293}
294
295impl fmt::Display for DecodeError {
296 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
297 write!(f, "byte {}: {}", self.offset, self.message)
298 }
299}
300
301impl std::error::Error for DecodeError {}
302
303pub fn decode(bytes: &[u8]) -> Result<Value, DecodeError> {
305 let mut d = Decoder::open(bytes)?;
306 let v = d.value(0)?;
307 d.end()?;
308 Ok(v)
309}
310
311pub fn decode_ref<'a>(bytes: &'a [u8], arena: &'a Bump) -> Result<ValueRef<'a>, DecodeError> {
315 let mut d = Decoder::open(bytes)?;
316 let mut stack = Vec::new();
317 let v = d.value_ref(0, arena, &mut stack)?;
318 d.end()?;
319 Ok(v)
320}
321
322impl<'b> Decoder<'b> {
323 fn open(bytes: &'b [u8]) -> Result<Self, DecodeError> {
325 let mut d = Decoder {
326 b: bytes,
327 i: 0,
328 strings: Vec::new(),
329 keys: Vec::new(),
330 };
331 if !bytes.starts_with(MAGIC) {
332 return Err(d.error("not Yog Data (no `YOGD` header)"));
333 }
334 d.i = 4;
335 let version = d.byte()?;
336 if version != VERSION {
337 return Err(d.error(format!(
338 "Yog Data version {version}, this reads version {VERSION}"
339 )));
340 }
341 let count = d.count(1)?;
342 d.strings.reserve(count);
343 for _ in 0..count {
344 let len = d.count(1)?;
345 let start = d.i;
346 let s = std::str::from_utf8(&bytes[start..start + len]).map_err(|_| DecodeError {
347 message: "a string isn't UTF-8".into(),
348 offset: start,
349 })?;
350 d.strings.push(s);
351 d.i += len;
352 }
353 Ok(d)
354 }
355
356 fn end(&self) -> Result<(), DecodeError> {
357 if self.i != self.b.len() {
358 return Err(self.error("bytes after the value"));
359 }
360 Ok(())
361 }
362}
363
364struct Decoder<'b> {
365 b: &'b [u8],
366 i: usize,
367 strings: Vec<&'b str>,
368 keys: Vec<Option<std::sync::Arc<str>>>,
370}
371
372impl<'b> Decoder<'b> {
373 fn error(&self, message: impl Into<String>) -> DecodeError {
374 DecodeError {
375 message: message.into(),
376 offset: self.i,
377 }
378 }
379
380 fn byte(&mut self) -> Result<u8, DecodeError> {
381 let b = *self
382 .b
383 .get(self.i)
384 .ok_or_else(|| self.error("unexpected end"))?;
385 self.i += 1;
386 Ok(b)
387 }
388
389 fn varint(&mut self) -> Result<u64, DecodeError> {
390 let mut n = 0u64;
391 for shift in (0..64).step_by(7) {
392 let b = self.byte()?;
393 n |= ((b & 0x7F) as u64) << shift;
394 if b & 0x80 == 0 {
395 return Ok(n);
396 }
397 }
398 Err(self.error("varint longer than 64 bits"))
399 }
400
401 fn count(&mut self, min: usize) -> Result<usize, DecodeError> {
403 let n = self.varint()?;
404 let left = self.b.len() - self.i;
405 if n > (left / min.max(1)) as u64 {
406 return Err(self.error(format!("length {n} past the end ({left} bytes left)")));
407 }
408 Ok(n as usize)
409 }
410
411 fn fixed<const N: usize>(&mut self) -> Result<[u8; N], DecodeError> {
412 let bytes = self
413 .b
414 .get(self.i..self.i + N)
415 .ok_or_else(|| self.error("unexpected end"))?;
416 self.i += N;
417 Ok(bytes.try_into().unwrap())
418 }
419
420 fn string(&mut self) -> Result<&'b str, DecodeError> {
421 let i = self.varint()?;
422 self.strings
423 .get(i as usize)
424 .copied()
425 .ok_or_else(|| self.error(format!("string {i} isn't in the table")))
426 }
427
428 fn key(&mut self) -> Result<std::sync::Arc<str>, DecodeError> {
430 let i = self.varint()? as usize;
431 if let Some(Some(k)) = self.keys.get(i) {
432 return Ok(k.clone());
433 }
434 let s = *self.strings.get(i).ok_or_else(|| self.error(format!("string {i} isn't in the table")))?;
435 let k: std::sync::Arc<str> = s.into();
436 if self.keys.len() <= i {
437 self.keys.resize(self.strings.len(), None);
438 }
439 self.keys[i] = Some(k.clone());
440 Ok(k)
441 }
442
443 fn value_ref<'a>(&mut self, depth: usize, arena: &'a Bump, stack: &mut Vec<ValueRef<'a>>) -> Result<ValueRef<'a>, DecodeError>
446 where
447 'b: 'a,
448 {
449 if depth > MAX_DEPTH {
450 return Err(self.error(format!("nested deeper than {MAX_DEPTH} levels")));
451 }
452 Ok(match self.byte()? {
453 tag::NULL => ValueRef::Null,
454 tag::FALSE => ValueRef::Bool(false),
455 tag::TRUE => ValueRef::Bool(true),
456 tag::INT => {
457 let z = self.varint()?;
458 ValueRef::Int(((z >> 1) as i64) ^ -((z & 1) as i64))
459 }
460 tag::FLOAT => ValueRef::Float(f64::from_le_bytes(self.fixed()?)),
461 tag::STR => ValueRef::Str(self.string()?),
462 tag::LIST => {
463 let n = self.count(1)?;
464 let start = stack.len();
465 for _ in 0..n {
466 let v = self.value_ref(depth + 1, arena, stack)?;
467 stack.push(v);
468 }
469 let items = arena.alloc_slice_copy(&stack[start..]);
470 stack.truncate(start);
471 ValueRef::List(items)
472 }
473 tag::MAP => {
474 let n = self.count(2)?;
475 let mut entries = bumpalo::collections::Vec::with_capacity_in(n, arena);
476 for _ in 0..n {
477 let k = self.string()?;
478 entries.push((k, self.value_ref(depth + 1, arena, stack)?));
479 }
480 ValueRef::Map(MapRef(entries.into_bump_slice()))
481 }
482 t @ (tag::REF | tag::TAG) => {
483 let (kind, id) = (self.string()?, self.string()?);
484 if t == tag::REF { ValueRef::Ref { kind, id } } else { ValueRef::Tag { kind, id } }
485 }
486 tag::RES => ValueRef::Res { set: self.string()?, key: self.string()? },
487 tag::TEXT => ValueRef::Text(self.string()?),
488 tag::IMAGE => ValueRef::Image(self.string()?),
489 tag::COLOR => ValueRef::Color(u32::from_le_bytes(self.fixed()?)),
490 tag::LANG => ValueRef::Lang(self.string()?),
491 t => {
492 self.i -= 1;
493 return Err(self.error(format!("unknown tag {t}")));
494 }
495 })
496 }
497
498 fn value(&mut self, depth: usize) -> Result<Value, DecodeError> {
499 if depth > MAX_DEPTH {
500 return Err(self.error(format!("nested deeper than {MAX_DEPTH} levels")));
501 }
502 Ok(match self.byte()? {
503 tag::NULL => Value::Null,
504 tag::FALSE => Value::Bool(false),
505 tag::TRUE => Value::Bool(true),
506 tag::INT => {
507 let z = self.varint()?;
508 Value::Int(((z >> 1) as i64) ^ -((z & 1) as i64))
509 }
510 tag::FLOAT => Value::Float(f64::from_le_bytes(self.fixed()?)),
511 tag::STR => Value::Str(self.string()?.to_string()),
512 tag::LIST => {
513 let n = self.count(1)?;
514 let mut items = Vec::with_capacity(n);
515 for _ in 0..n {
516 items.push(self.value(depth + 1)?);
517 }
518 Value::List(items)
519 }
520 tag::MAP => {
521 let n = self.count(2)?;
522 let mut map = Map::with_capacity(n);
523 for _ in 0..n {
524 let k = self.key()?;
525 map.push_unchecked(k, self.value(depth + 1)?);
526 }
527 Value::Map(map)
528 }
529 t @ (tag::REF | tag::TAG) => {
530 let r = Ref {
531 kind: self.string()?.to_string(),
532 id: self.string()?.to_string(),
533 };
534 if t == tag::REF {
535 Value::Ref(r)
536 } else {
537 Value::Tag(r)
538 }
539 }
540 tag::RES => Value::Res(Res {
541 set: self.string()?.to_string(),
542 key: self.string()?.to_string(),
543 }),
544 tag::TEXT => Value::Text(self.string()?.to_string()),
545 tag::IMAGE => Value::Image(self.string()?.to_string()),
546 tag::COLOR => Value::Color(u32::from_le_bytes(self.fixed()?)),
547 tag::LANG => Value::Lang(self.string()?.to_string()),
548 t => {
549 self.i -= 1;
550 return Err(self.error(format!("unknown tag {t}")));
551 }
552 })
553 }
554}
555
556#[cfg(test)]
557mod tests {
558 use super::*;
559
560 fn sample() -> Value {
561 let mut m = Map::new();
562 m.insert("name", Value::Str("Ruby".into()));
563 m.insert(
564 "n",
565 Value::List(vec![
566 Value::Int(0),
567 Value::Int(-1),
568 Value::Int(i64::MAX),
569 Value::Int(i64::MIN),
570 Value::Float(0.5),
571 Value::Null,
572 Value::Bool(true),
573 Value::Bool(false),
574 ]),
575 );
576 m.insert("item", Value::Ref(Ref::new("item", "minecraft:stick")));
577 m.insert("tag", Value::Tag(Ref::new("item", "minecraft:planks")));
578 m.insert(
579 "title",
580 Value::Res(Res {
581 set: "Strings".into(),
582 key: "title".into(),
583 }),
584 );
585 m.insert("text", Value::Text("{b|hi}".into()));
586 m.insert("icon", Value::Image("sprite:x".into()));
587 m.insert("color", Value::Color(0x80FF0000));
588 m.insert("lang", Value::Lang("gui.done".into()));
589 m.insert("again", Value::Str("Ruby".into()));
590 Value::Map(m)
591 }
592
593 #[test]
594 fn round_trips_every_type() {
595 let v = sample();
596 let bytes = encode(&v);
597 assert_eq!(decode(&bytes).unwrap(), v);
598 assert_eq!(bytes.windows(4).filter(|w| w == b"Ruby").count(), 1);
600 }
601
602 #[test]
603 fn the_borrowed_decode_reads_the_same_without_copying() {
604 let v = sample();
605 let bytes = encode(&v);
606 let arena = Bump::new();
607 let r = decode_ref(&bytes, &arena).unwrap();
608 assert_eq!(r.to_value(), v);
609 assert_eq!(r, v.borrow(&arena), "borrowing a Value gives the same");
610 let span = bytes.as_ptr_range();
612 let mut strings = Vec::new();
613 fn walk<'a>(v: &ValueRef<'a>, out: &mut Vec<&'a str>) {
614 match v {
615 ValueRef::Str(s) | ValueRef::Text(s) | ValueRef::Image(s) | ValueRef::Lang(s) => out.push(s),
616 ValueRef::List(l) => l.iter().for_each(|x| walk(x, out)),
617 ValueRef::Map(m) => m.iter().for_each(|(k, x)| {
618 out.push(k);
619 walk(x, out)
620 }),
621 _ => {}
622 }
623 }
624 walk(&r, &mut strings);
625 assert!(!strings.is_empty() && strings.iter().all(|s| span.contains(&s.as_ptr())));
626 for len in 0..bytes.len() {
628 assert!(decode_ref(&bytes[..len], &arena).is_err(), "truncated at {len}");
629 }
630 }
631
632 #[test]
633 fn malformed_bytes_are_errors() {
634 let bytes = encode(&sample());
635 for len in 0..bytes.len() {
637 assert!(decode(&bytes[..len]).is_err(), "truncated at {len}");
638 }
639 let mut extra = bytes.clone();
640 extra.push(0);
641 assert!(
642 decode(&extra)
643 .unwrap_err()
644 .message
645 .contains("after the value")
646 );
647 assert!(
648 decode(b"YOGD\x02\x00\x00")
649 .unwrap_err()
650 .message
651 .contains("version 2")
652 );
653 assert!(
654 decode(b"YOGD\x01\x00\x63")
655 .unwrap_err()
656 .message
657 .contains("unknown tag")
658 );
659 assert!(
660 decode(b"YOGD\x01\x00\x05\x00")
661 .unwrap_err()
662 .message
663 .contains("isn't in the table")
664 );
665 assert!(
667 decode(b"YOGD\x01\x00\x06\xff\xff\xff\xff\x0f")
668 .unwrap_err()
669 .message
670 .contains("past the end")
671 );
672 let deep: Vec<u8> = b"YOGD\x01\x00"
673 .iter()
674 .copied()
675 .chain(std::iter::repeat_n([6u8, 1], 300).flatten())
676 .chain([0])
677 .collect();
678 assert!(decode(&deep).unwrap_err().message.contains("nested deeper"));
679 }
680}