strict_encoding/
traits.rs

1// Strict encoding library for deterministic binary serialization.
2//
3// SPDX-License-Identifier: Apache-2.0
4//
5// Designed in 2019-2025 by Dr Maxim Orlovsky <orlovsky@ubideco.org>
6// Written in 2024-2025 by Dr Maxim Orlovsky <orlovsky@ubideco.org>
7//
8// Copyright (C) 2022-2025 Laboratories for Ubiquitous Deterministic Computing (UBIDECO),
9//                         Institute for Distributed and Cognitive Systems (InDCS), Switzerland.
10// Copyright (C) 2022-2025 Dr Maxim Orlovsky.
11// All rights under the above copyrights are reserved.
12//
13// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
14// in compliance with the License. You may obtain a copy of the License at
15//
16//        http://www.apache.org/licenses/LICENSE-2.0
17//
18// Unless required by applicable law or agreed to in writing, software distributed under the License
19// is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
20// or implied. See the License for the specific language governing permissions and limitations under
21// the License.
22
23use std::io::{BufRead, Seek};
24use std::marker::PhantomData;
25use std::{fs, io};
26
27use amplify::confinement::{Collection, Confined};
28use amplify::num::u24;
29use amplify::Wrapper;
30
31use super::{DecodeError, DecodeRawLe, VariantName};
32use crate::reader::StreamReader;
33use crate::writer::StreamWriter;
34use crate::{
35    DeserializeError, FieldName, Primitive, SerializeError, Sizing, StrictDumb, StrictEnum,
36    StrictReader, StrictStruct, StrictSum, StrictTuple, StrictType, StrictUnion, StrictWriter,
37};
38
39pub trait TypedParent: Sized {}
40
41pub trait WriteRaw {
42    fn write_raw<const MAX_LEN: usize>(&mut self, bytes: impl AsRef<[u8]>) -> io::Result<()>;
43    fn write_raw_array<const LEN: usize>(&mut self, raw: [u8; LEN]) -> io::Result<()> {
44        self.write_raw::<LEN>(raw)
45    }
46    fn write_raw_len<const MAX_LEN: usize>(&mut self, len: usize) -> io::Result<()> {
47        match MAX_LEN {
48            tiny if tiny <= u8::MAX as usize => self.write_raw_array((len as u8).to_le_bytes()),
49            small if small <= u16::MAX as usize => self.write_raw_array((len as u16).to_le_bytes()),
50            medium if medium <= u24::MAX.into_usize() => {
51                self.write_raw_array((u24::with(len as u32)).to_le_bytes())
52            }
53            large if large <= u32::MAX as usize => self.write_raw_array((len as u32).to_le_bytes()),
54            huge if huge <= u64::MAX as usize => self.write_raw_array((len as u64).to_le_bytes()),
55            _ => unreachable!("confined collections larger than u64::MAX must not exist"),
56        }
57    }
58}
59
60impl<T: WriteRaw> WriteRaw for &mut T {
61    fn write_raw<const MAX_LEN: usize>(&mut self, bytes: impl AsRef<[u8]>) -> io::Result<()> {
62        (*self).write_raw::<MAX_LEN>(bytes)
63    }
64}
65
66#[allow(unused_variables)]
67pub trait TypedWrite: Sized {
68    type TupleWriter: WriteTuple<Parent = Self>;
69    type StructWriter: WriteStruct<Parent = Self>;
70    type UnionDefiner: DefineUnion<Parent = Self>;
71    type RawWriter: WriteRaw;
72
73    #[doc(hidden)]
74    unsafe fn raw_writer(&mut self) -> &mut Self::RawWriter;
75
76    fn write_union<T: StrictUnion>(
77        self,
78        inner: impl FnOnce(Self::UnionDefiner) -> io::Result<Self>,
79    ) -> io::Result<Self>;
80    fn write_enum<T: StrictEnum>(self, value: T) -> io::Result<Self>
81    where u8: From<T>;
82    fn write_tuple<T: StrictTuple>(
83        self,
84        inner: impl FnOnce(Self::TupleWriter) -> io::Result<Self>,
85    ) -> io::Result<Self>;
86    fn write_struct<T: StrictStruct>(
87        self,
88        inner: impl FnOnce(Self::StructWriter) -> io::Result<Self>,
89    ) -> io::Result<Self>;
90    fn write_newtype<T: StrictTuple>(self, value: &impl StrictEncode) -> io::Result<Self> {
91        self.write_tuple::<T>(|writer| Ok(writer.write_field(value)?.complete()))
92    }
93
94    #[doc(hidden)]
95    unsafe fn register_primitive(self, prim: Primitive) -> Self { self }
96    #[doc(hidden)]
97    unsafe fn register_array(self, ty: &impl StrictEncode, len: u16) -> Self { self }
98    #[doc(hidden)]
99    unsafe fn register_unicode(self, sizing: Sizing) -> Self { self }
100    #[doc(hidden)]
101    #[deprecated(since = "2.3.1", note = "use register_rstring")]
102    unsafe fn register_ascii(self, sizing: Sizing) -> Self {
103        panic!("TypedWrite::register_ascii must not be called; pls see compilation warnings")
104    }
105    #[doc(hidden)]
106    unsafe fn register_rstring(
107        self,
108        c: &impl StrictEncode,
109        c1: &impl StrictEncode,
110        sizing: Sizing,
111    ) -> Self {
112        self
113    }
114    #[doc(hidden)]
115    unsafe fn register_list(self, ty: &impl StrictEncode, sizing: Sizing) -> Self { self }
116    #[doc(hidden)]
117    unsafe fn register_set(self, ty: &impl StrictEncode, sizing: Sizing) -> Self { self }
118    #[doc(hidden)]
119    unsafe fn register_map(
120        self,
121        ket: &impl StrictEncode,
122        ty: &impl StrictEncode,
123        sizing: Sizing,
124    ) -> Self {
125        self
126    }
127
128    /// Used by unicode strings, ASCII strings and restricted char set strings.
129    #[doc(hidden)]
130    unsafe fn write_string<const MAX_LEN: usize>(
131        mut self,
132        bytes: impl AsRef<[u8]>,
133    ) -> io::Result<Self> {
134        self.raw_writer().write_raw_len::<MAX_LEN>(bytes.as_ref().len())?;
135        self.raw_writer().write_raw::<MAX_LEN>(bytes)?;
136        Ok(self)
137    }
138
139    /// Vec and sets - excluding strings, written by [`Self::write_string`].
140    #[doc(hidden)]
141    unsafe fn write_collection<C: Collection, const MIN_LEN: usize, const MAX_LEN: usize>(
142        mut self,
143        col: &Confined<C, MIN_LEN, MAX_LEN>,
144    ) -> io::Result<Self>
145    where
146        for<'a> &'a C: IntoIterator,
147        for<'a> <&'a C as IntoIterator>::Item: StrictEncode,
148    {
149        self.raw_writer().write_raw_len::<MAX_LEN>(col.len())?;
150        for item in col {
151            self = item.strict_encode(self)?;
152        }
153        Ok(self)
154    }
155
156    // TODO: Do `write_keyed_collection`
157}
158
159pub trait ReadRaw {
160    fn read_raw<const MAX_LEN: usize>(&mut self, len: usize) -> io::Result<Vec<u8>>;
161
162    fn read_raw_array<const LEN: usize>(&mut self) -> io::Result<[u8; LEN]>;
163
164    fn read_raw_len<const MAX_LEN: usize>(&mut self) -> Result<usize, DecodeError> {
165        Ok(match MAX_LEN {
166            tiny if tiny <= u8::MAX as usize => u8::decode_raw_le(self)? as usize,
167            small if small <= u16::MAX as usize => u16::decode_raw_le(self)? as usize,
168            medium if medium <= u24::MAX.into_usize() => u24::decode_raw_le(self)?.into_usize(),
169            large if large <= u32::MAX as usize => u32::decode_raw_le(self)? as usize,
170            huge if huge <= u64::MAX as usize => u64::decode_raw_le(self)? as usize,
171            _ => unreachable!("confined collections larger than u64::MAX must not exist"),
172        })
173    }
174}
175
176impl<T: ReadRaw> ReadRaw for &mut T {
177    fn read_raw<const MAX_LEN: usize>(&mut self, len: usize) -> io::Result<Vec<u8>> {
178        (*self).read_raw::<MAX_LEN>(len)
179    }
180
181    fn read_raw_array<const LEN: usize>(&mut self) -> io::Result<[u8; LEN]> {
182        (*self).read_raw_array::<LEN>()
183    }
184}
185
186pub trait TypedRead {
187    type TupleReader<'parent>: ReadTuple
188    where Self: 'parent;
189    type StructReader<'parent>: ReadStruct
190    where Self: 'parent;
191    type UnionReader: ReadUnion;
192    type RawReader: ReadRaw;
193
194    #[doc(hidden)]
195    unsafe fn raw_reader(&mut self) -> &mut Self::RawReader;
196
197    fn read_union<T: StrictUnion>(
198        &mut self,
199        inner: impl FnOnce(VariantName, &mut Self::UnionReader) -> Result<T, DecodeError>,
200    ) -> Result<T, DecodeError>;
201
202    fn read_enum<T: StrictEnum>(&mut self) -> Result<T, DecodeError>
203    where u8: From<T>;
204
205    fn read_tuple<'parent, 'me, T: StrictTuple>(
206        &'me mut self,
207        inner: impl FnOnce(&mut Self::TupleReader<'parent>) -> Result<T, DecodeError>,
208    ) -> Result<T, DecodeError>
209    where
210        Self: 'parent,
211        'me: 'parent;
212
213    fn read_struct<'parent, 'me, T: StrictStruct>(
214        &'me mut self,
215        inner: impl FnOnce(&mut Self::StructReader<'parent>) -> Result<T, DecodeError>,
216    ) -> Result<T, DecodeError>
217    where
218        Self: 'parent,
219        'me: 'parent;
220
221    fn read_newtype<T: StrictTuple + Wrapper>(&mut self) -> Result<T, DecodeError>
222    where T::Inner: StrictDecode {
223        self.read_tuple(|reader| reader.read_field().map(T::from_inner))
224    }
225
226    #[doc(hidden)]
227    unsafe fn read_string<const MAX_LEN: usize>(&mut self) -> Result<Vec<u8>, DecodeError> {
228        let len = self.raw_reader().read_raw_len::<MAX_LEN>()?;
229        self.raw_reader().read_raw::<MAX_LEN>(len).map_err(DecodeError::from)
230    }
231}
232
233pub trait DefineTuple: Sized {
234    type Parent: TypedParent;
235    fn define_field<T: StrictEncode + StrictDumb>(self) -> Self;
236    fn complete(self) -> Self::Parent;
237}
238
239pub trait WriteTuple: Sized {
240    type Parent: TypedParent;
241    fn write_field(self, value: &impl StrictEncode) -> io::Result<Self>;
242    fn complete(self) -> Self::Parent;
243}
244
245pub trait ReadTuple {
246    fn read_field<T: StrictDecode>(&mut self) -> Result<T, DecodeError>;
247}
248
249pub trait DefineStruct: Sized {
250    type Parent: TypedParent;
251    fn define_field<T: StrictEncode + StrictDumb>(self, name: FieldName) -> Self;
252    fn complete(self) -> Self::Parent;
253}
254
255pub trait WriteStruct: Sized {
256    type Parent: TypedParent;
257    fn write_field(self, name: FieldName, value: &impl StrictEncode) -> io::Result<Self>;
258    fn complete(self) -> Self::Parent;
259}
260
261pub trait ReadStruct {
262    fn read_field<T: StrictDecode>(&mut self, field: FieldName) -> Result<T, DecodeError>;
263}
264
265pub trait DefineEnum: Sized {
266    type Parent: TypedWrite;
267    type EnumWriter: WriteEnum<Parent = Self::Parent>;
268    fn define_variant(self, name: VariantName) -> Self;
269    fn complete(self) -> Self::EnumWriter;
270}
271
272pub trait WriteEnum: Sized {
273    type Parent: TypedWrite;
274    fn write_variant(self, name: VariantName) -> io::Result<Self>;
275    fn complete(self) -> Self::Parent;
276}
277
278pub trait DefineUnion: Sized {
279    type Parent: TypedWrite;
280    type TupleDefiner: DefineTuple<Parent = Self>;
281    type StructDefiner: DefineStruct<Parent = Self>;
282    type UnionWriter: WriteUnion<Parent = Self::Parent>;
283
284    fn define_unit(self, name: VariantName) -> Self;
285    fn define_newtype<T: StrictEncode + StrictDumb>(self, name: VariantName) -> Self {
286        self.define_tuple(name, |definer| definer.define_field::<T>().complete())
287    }
288    fn define_tuple(
289        self,
290        name: VariantName,
291        inner: impl FnOnce(Self::TupleDefiner) -> Self,
292    ) -> Self;
293    fn define_struct(
294        self,
295        name: VariantName,
296        inner: impl FnOnce(Self::StructDefiner) -> Self,
297    ) -> Self;
298
299    fn complete(self) -> Self::UnionWriter;
300}
301
302pub trait WriteUnion: Sized {
303    type Parent: TypedWrite;
304    type TupleWriter: WriteTuple<Parent = Self>;
305    type StructWriter: WriteStruct<Parent = Self>;
306
307    fn write_unit(self, name: VariantName) -> io::Result<Self>;
308    fn write_newtype(self, name: VariantName, value: &impl StrictEncode) -> io::Result<Self> {
309        self.write_tuple(name, |writer| Ok(writer.write_field(value)?.complete()))
310    }
311    fn write_tuple(
312        self,
313        name: VariantName,
314        inner: impl FnOnce(Self::TupleWriter) -> io::Result<Self>,
315    ) -> io::Result<Self>;
316    fn write_struct(
317        self,
318        name: VariantName,
319        inner: impl FnOnce(Self::StructWriter) -> io::Result<Self>,
320    ) -> io::Result<Self>;
321
322    fn complete(self) -> Self::Parent;
323}
324
325pub trait ReadUnion: Sized {
326    type TupleReader<'parent>: ReadTuple
327    where Self: 'parent;
328    type StructReader<'parent>: ReadStruct
329    where Self: 'parent;
330
331    fn read_tuple<'parent, 'me, T: StrictSum>(
332        &'me mut self,
333        inner: impl FnOnce(&mut Self::TupleReader<'parent>) -> Result<T, DecodeError>,
334    ) -> Result<T, DecodeError>
335    where
336        Self: 'parent,
337        'me: 'parent;
338
339    fn read_struct<'parent, 'me, T: StrictSum>(
340        &'me mut self,
341        inner: impl FnOnce(&mut Self::StructReader<'parent>) -> Result<T, DecodeError>,
342    ) -> Result<T, DecodeError>
343    where
344        Self: 'parent,
345        'me: 'parent;
346
347    fn read_newtype<T: StrictSum + From<I>, I: StrictDecode>(&mut self) -> Result<T, DecodeError> {
348        self.read_tuple(|reader| reader.read_field::<I>().map(T::from))
349    }
350}
351
352pub trait StrictEncode: StrictType {
353    fn strict_encode<W: TypedWrite>(&self, writer: W) -> io::Result<W>;
354    fn strict_write(&self, writer: impl WriteRaw) -> io::Result<()> {
355        let w = StrictWriter::with(writer);
356        self.strict_encode(w)?;
357        Ok(())
358    }
359}
360
361pub trait StrictDecode: StrictType {
362    fn strict_decode(reader: &mut impl TypedRead) -> Result<Self, DecodeError>;
363    fn strict_read(reader: impl ReadRaw) -> Result<Self, DecodeError> {
364        let mut r = StrictReader::with(reader);
365        Self::strict_decode(&mut r)
366    }
367}
368
369impl<T: StrictEncode> StrictEncode for &T {
370    fn strict_encode<W: TypedWrite>(&self, writer: W) -> io::Result<W> {
371        (*self).strict_encode(writer)
372    }
373}
374
375impl<T> StrictEncode for PhantomData<T> {
376    fn strict_encode<W: TypedWrite>(&self, writer: W) -> io::Result<W> { Ok(writer) }
377}
378
379impl<T> StrictDecode for PhantomData<T> {
380    fn strict_decode(_reader: &mut impl TypedRead) -> Result<Self, DecodeError> { Ok(default!()) }
381}
382
383pub trait StrictSerialize: StrictEncode {
384    fn strict_serialized_len<const MAX: usize>(&self) -> io::Result<usize> {
385        let counter = StrictWriter::counter::<MAX>();
386        Ok(self.strict_encode(counter)?.unbox().unconfine().count)
387    }
388
389    fn to_strict_serialized<const MAX: usize>(
390        &self,
391    ) -> Result<Confined<Vec<u8>, 0, MAX>, SerializeError> {
392        let ast_data = StrictWriter::in_memory::<MAX>();
393        let data = self.strict_encode(ast_data)?.unbox().unconfine();
394        Confined::<Vec<u8>, 0, MAX>::try_from(data).map_err(SerializeError::from)
395    }
396
397    fn strict_serialize_to_file<const MAX: usize>(
398        &self,
399        path: impl AsRef<std::path::Path>,
400    ) -> Result<(), SerializeError> {
401        let file = fs::File::create(path)?;
402        // TODO: Do FileReader
403        let file = StrictWriter::with(StreamWriter::new::<MAX>(file));
404        self.strict_encode(file)?;
405        Ok(())
406    }
407}
408
409pub trait StrictDeserialize: StrictDecode {
410    fn from_strict_serialized<const MAX: usize>(
411        ast_data: Confined<Vec<u8>, 0, MAX>,
412    ) -> Result<Self, DeserializeError> {
413        let mut reader = StrictReader::in_memory::<MAX>(ast_data);
414        let me = Self::strict_decode(&mut reader)?;
415        let mut cursor = reader.into_cursor();
416        if !cursor.fill_buf()?.is_empty() {
417            return Err(DeserializeError::DataNotEntirelyConsumed);
418        }
419        Ok(me)
420    }
421
422    fn strict_deserialize_from_file<const MAX: usize>(
423        path: impl AsRef<std::path::Path>,
424    ) -> Result<Self, DeserializeError> {
425        let file = fs::File::open(path)?;
426        // TODO: Do FileReader
427        let mut reader = StrictReader::with(StreamReader::new::<MAX>(file));
428        let me = Self::strict_decode(&mut reader)?;
429        let mut file = reader.unbox().unconfine();
430        if file.stream_position()? != file.seek(io::SeekFrom::End(0))? {
431            return Err(DeserializeError::DataNotEntirelyConsumed);
432        }
433        Ok(me)
434    }
435}