Skip to main content

ssp2/
primitives.rs

1//! Conventions primitives (SPEC.md "Conventions and primitive encodings"):
2//! little-endian fixed-width integers, `str`, `bytes`, `opt`, `bool`, `json`,
3//! canonical maps. Shared by the envelope codec and the SSG2 segment codec.
4
5use crate::error::{DecodeError, Result};
6use crate::util::utf16_lt;
7
8/// JS safe-integer contract: `i64` values must be within ±(2^53 − 1).
9pub const I64_SAFE_MAX: i64 = 9_007_199_254_740_991;
10
11/// A raw `json`-typed value: validated to parse as a JSON document at decode
12/// time, but preserved byte-for-byte (host-opaque; round-trip fidelity, never
13/// re-canonicalization — Conventions `json` row).
14#[derive(Debug, Clone, PartialEq, Eq)]
15pub struct RawJson(pub String);
16
17impl RawJson {
18    pub fn parse(&self) -> serde_json::Value {
19        // Validated at construction; a parse failure here is a codec bug.
20        serde_json::from_str(&self.0).expect("RawJson holds validated JSON")
21    }
22}
23
24pub struct Reader<'a> {
25    buf: &'a [u8],
26    pos: usize,
27}
28
29impl<'a> Reader<'a> {
30    pub fn new(buf: &'a [u8]) -> Self {
31        Reader { buf, pos: 0 }
32    }
33
34    pub fn remaining(&self) -> usize {
35        self.buf.len() - self.pos
36    }
37
38    pub fn is_empty(&self) -> bool {
39        self.remaining() == 0
40    }
41
42    pub fn take(&mut self, n: usize, what: &str) -> Result<&'a [u8]> {
43        if n > self.remaining() {
44            return Err(DecodeError::invalid(format!(
45                "truncated: need {n} bytes for {what}, have {}",
46                self.remaining()
47            )));
48        }
49        let s = &self.buf[self.pos..self.pos + n];
50        self.pos += n;
51        Ok(s)
52    }
53
54    pub fn u8(&mut self, what: &str) -> Result<u8> {
55        Ok(self.take(1, what)?[0])
56    }
57
58    pub fn u16(&mut self, what: &str) -> Result<u16> {
59        let b = self.take(2, what)?;
60        Ok(u16::from_le_bytes([b[0], b[1]]))
61    }
62
63    pub fn u32(&mut self, what: &str) -> Result<u32> {
64        let b = self.take(4, what)?;
65        Ok(u32::from_le_bytes([b[0], b[1], b[2], b[3]]))
66    }
67
68    pub fn i32(&mut self, what: &str) -> Result<i32> {
69        let b = self.take(4, what)?;
70        Ok(i32::from_le_bytes([b[0], b[1], b[2], b[3]]))
71    }
72
73    pub fn i64(&mut self, what: &str) -> Result<i64> {
74        let b = self.take(8, what)?;
75        let v = i64::from_le_bytes([b[0], b[1], b[2], b[3], b[4], b[5], b[6], b[7]]);
76        if !(-I64_SAFE_MAX..=I64_SAFE_MAX).contains(&v) {
77            return Err(DecodeError::invalid(format!(
78                "i64 field {what} = {v} outside the ±(2^53−1) safe-integer contract"
79            )));
80        }
81        Ok(v)
82    }
83
84    pub fn f64(&mut self, what: &str) -> Result<f64> {
85        let b = self.take(8, what)?;
86        Ok(f64::from_le_bytes([
87            b[0], b[1], b[2], b[3], b[4], b[5], b[6], b[7],
88        ]))
89    }
90
91    pub fn bool(&mut self, what: &str) -> Result<bool> {
92        match self.u8(what)? {
93            0x00 => Ok(false),
94            0x01 => Ok(true),
95            other => Err(DecodeError::invalid(format!(
96                "bool field {what} has byte 0x{other:02x} (only 0x00/0x01 are valid)"
97            ))),
98        }
99    }
100
101    /// `opt(T)` presence byte: 0x00 absent, 0x01 present, anything else a
102    /// decode error.
103    pub fn presence(&mut self, what: &str) -> Result<bool> {
104        match self.u8(what)? {
105            0x00 => Ok(false),
106            0x01 => Ok(true),
107            other => Err(DecodeError::invalid(format!(
108                "opt presence byte for {what} is 0x{other:02x} (only 0x00/0x01 are valid)"
109            ))),
110        }
111    }
112
113    pub fn str(&mut self, what: &str) -> Result<String> {
114        let len = self.u32(what)? as usize;
115        let raw = self.take(len, what)?;
116        match std::str::from_utf8(raw) {
117            Ok(s) => Ok(s.to_owned()),
118            Err(_) => Err(DecodeError::invalid(format!(
119                "str field {what} is not well-formed UTF-8"
120            ))),
121        }
122    }
123
124    pub fn bytes(&mut self, what: &str) -> Result<Vec<u8>> {
125        let len = self.u32(what)? as usize;
126        Ok(self.take(len, what)?.to_vec())
127    }
128
129    /// `json`: a `str` that must parse as a JSON document; the raw string is
130    /// preserved verbatim for round-trip fidelity.
131    pub fn json(&mut self, what: &str) -> Result<RawJson> {
132        let s = self.str(what)?;
133        if serde_json::from_str::<serde_json::Value>(&s).is_err() {
134            return Err(DecodeError::invalid(format!(
135                "json field {what} does not parse as a JSON document"
136            )));
137        }
138        Ok(RawJson(s))
139    }
140
141    /// `blob_ref` (§2.4 tag 7, §5.9.1): a `str` holding a canonical BlobRef
142    /// document; validated at decode, raw string preserved for round-trip.
143    pub fn blob_ref(&mut self, what: &str) -> Result<RawJson> {
144        let s = self.str(what)?;
145        crate::blob_ref::validate_blob_ref(&s)?;
146        Ok(RawJson(s))
147    }
148
149    /// `map` of `str` → `list(str)`. Keys must be unique and in ascending
150    /// code-unit order (canonical encoding); a violation is a decode error.
151    pub fn scope_map(&mut self, what: &str) -> Result<Vec<(String, Vec<String>)>> {
152        let count = self.u32(what)? as usize;
153        let mut entries: Vec<(String, Vec<String>)> = Vec::with_capacity(count.min(1024));
154        for _ in 0..count {
155            let key = self.str(what)?;
156            self.check_key_order(&entries.last().map(|(k, _)| k.as_str()), &key, what)?;
157            let n = self.u32(what)? as usize;
158            let mut values = Vec::with_capacity(n.min(1024));
159            for _ in 0..n {
160                values.push(self.str(what)?);
161            }
162            entries.push((key, values));
163        }
164        Ok(entries)
165    }
166
167    /// `map` of `str` → `str`, same canonical key rules.
168    pub fn str_map(&mut self, what: &str) -> Result<Vec<(String, String)>> {
169        let count = self.u32(what)? as usize;
170        let mut entries: Vec<(String, String)> = Vec::with_capacity(count.min(1024));
171        for _ in 0..count {
172            let key = self.str(what)?;
173            self.check_key_order(&entries.last().map(|(k, _)| k.as_str()), &key, what)?;
174            let value = self.str(what)?;
175            entries.push((key, value));
176        }
177        Ok(entries)
178    }
179
180    fn check_key_order(&self, prev: &Option<&str>, key: &str, what: &str) -> Result<()> {
181        if let Some(prev) = prev {
182            if !utf16_lt(prev, key) {
183                return Err(DecodeError::invalid(format!(
184                    "map {what}: key {key:?} is duplicate or out of canonical order after {prev:?}"
185                )));
186            }
187        }
188        Ok(())
189    }
190}
191
192#[derive(Default)]
193pub struct Writer {
194    buf: Vec<u8>,
195}
196
197impl Writer {
198    pub fn new() -> Self {
199        Writer::default()
200    }
201
202    pub fn into_bytes(self) -> Vec<u8> {
203        self.buf
204    }
205
206    pub fn raw(&mut self, bytes: &[u8]) {
207        self.buf.extend_from_slice(bytes);
208    }
209
210    pub fn u8(&mut self, v: u8) {
211        self.buf.push(v);
212    }
213
214    pub fn u16(&mut self, v: u16) {
215        self.buf.extend_from_slice(&v.to_le_bytes());
216    }
217
218    pub fn u32(&mut self, v: u32) {
219        self.buf.extend_from_slice(&v.to_le_bytes());
220    }
221
222    pub fn i32(&mut self, v: i32) {
223        self.buf.extend_from_slice(&v.to_le_bytes());
224    }
225
226    pub fn i64(&mut self, v: i64) {
227        self.buf.extend_from_slice(&v.to_le_bytes());
228    }
229
230    pub fn f64(&mut self, v: f64) {
231        self.buf.extend_from_slice(&v.to_le_bytes());
232    }
233
234    pub fn bool(&mut self, v: bool) {
235        self.buf.push(u8::from(v));
236    }
237
238    pub fn str(&mut self, s: &str) {
239        self.u32(s.len() as u32);
240        self.buf.extend_from_slice(s.as_bytes());
241    }
242
243    pub fn bytes(&mut self, b: &[u8]) {
244        self.u32(b.len() as u32);
245        self.buf.extend_from_slice(b);
246    }
247
248    pub fn opt<T>(&mut self, v: &Option<T>, mut write: impl FnMut(&mut Self, &T)) {
249        match v {
250            None => self.u8(0x00),
251            Some(inner) => {
252                self.u8(0x01);
253                write(self, inner);
254            }
255        }
256    }
257
258    pub fn scope_map(&mut self, m: &[(String, Vec<String>)]) {
259        self.u32(m.len() as u32);
260        for (k, vs) in m {
261            self.str(k);
262            self.u32(vs.len() as u32);
263            for v in vs {
264                self.str(v);
265            }
266        }
267    }
268
269    pub fn str_map(&mut self, m: &[(String, String)]) {
270        self.u32(m.len() as u32);
271        for (k, v) in m {
272            self.str(k);
273            self.str(v);
274        }
275    }
276}