strict_encoding/
embedded.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) 2019-2022 LNP/BP Standards Association.
9// Copyright (C) 2022-2025 Laboratories for Ubiquitous Deterministic Computing (UBIDECO),
10//                         Institute for Distributed and Cognitive Systems (InDCS), Switzerland.
11// Copyright (C) 2019-2025 Dr Maxim Orlovsky.
12// All rights under the above copyrights are reserved.
13//
14// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
15// in compliance with the License. You may obtain a copy of the License at
16//
17//        http://www.apache.org/licenses/LICENSE-2.0
18//
19// Unless required by applicable law or agreed to in writing, software distributed under the License
20// is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
21// or implied. See the License for the specific language governing permissions and limitations under
22// the License.
23
24use std::collections::{BTreeMap, BTreeSet, VecDeque};
25use std::hash::Hash;
26use std::io;
27use std::num::{NonZeroU128, NonZeroU16, NonZeroU32, NonZeroU64, NonZeroU8};
28
29use amplify::ascii::AsciiString;
30use amplify::confinement::Confined;
31#[cfg(feature = "float")]
32use amplify::num::apfloat::{ieee, Float};
33use amplify::num::{i1024, i256, i512, u1024, u24, u256, u40, u48, u512, u56};
34use amplify::{Array, Wrapper};
35
36use crate::stl::AsciiSym;
37use crate::{
38    DecodeError, DefineUnion, Primitive, RString, ReadRaw, ReadTuple, ReadUnion, RestrictedCharSet,
39    Sizing, StrictDecode, StrictDumb, StrictEncode, StrictProduct, StrictStruct, StrictSum,
40    StrictTuple, StrictType, StrictUnion, TypeName, TypedRead, TypedWrite, WriteRaw, WriteTuple,
41    WriteUnion, LIB_EMBEDDED,
42};
43
44pub trait DecodeRawLe: Sized {
45    fn decode_raw_le(reader: &mut (impl ReadRaw + ?Sized)) -> Result<Self, DecodeError>;
46}
47
48#[derive(
49    Wrapper, WrapperMut, Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash, Debug, Default, From
50)]
51#[wrapper(Display, FromStr, Octal, BitOps)]
52#[wrapper_mut(BitAssign)]
53#[derive(StrictType, StrictDecode)]
54#[strict_type(lib = LIB_EMBEDDED, crate = crate)]
55pub struct Byte(u8);
56
57impl StrictEncode for Byte {
58    fn strict_encode<W: TypedWrite>(&self, mut writer: W) -> io::Result<W> {
59        unsafe {
60            writer = writer.register_primitive(Primitive::BYTE);
61            writer.raw_writer().write_raw::<1>([self.0])?;
62        }
63        Ok(writer)
64    }
65}
66
67macro_rules! encode_num {
68    ($ty:ty, $id:ident) => {
69        impl $crate::StrictType for $ty {
70            const STRICT_LIB_NAME: &'static str = $crate::LIB_EMBEDDED;
71            fn strict_name() -> Option<TypeName> { Some(tn!(stringify!($id))) }
72        }
73        impl $crate::StrictEncode for $ty {
74            fn strict_encode<W: TypedWrite>(&self, mut writer: W) -> io::Result<W> {
75                unsafe {
76                    writer = writer.register_primitive(Primitive::$id);
77                    writer.raw_writer().write_raw_array(self.to_le_bytes())?;
78                }
79                Ok(writer)
80            }
81        }
82        impl $crate::DecodeRawLe for $ty {
83            fn decode_raw_le(reader: &mut (impl ReadRaw + ?Sized)) -> Result<Self, DecodeError> {
84                let buf = reader.read_raw_array::<{ Self::BITS as usize / 8 }>()?;
85                Ok(Self::from_le_bytes(buf))
86            }
87        }
88        impl $crate::StrictDecode for $ty {
89            fn strict_decode(reader: &mut impl TypedRead) -> Result<Self, DecodeError> {
90                Self::decode_raw_le(unsafe { reader.raw_reader() })
91            }
92        }
93    };
94}
95
96macro_rules! encode_nonzero {
97    ($ty:ty, $p:ty, $id:ident) => {
98        impl $crate::StrictType for $ty {
99            const STRICT_LIB_NAME: &'static str = $crate::LIB_EMBEDDED;
100            fn strict_name() -> Option<TypeName> { Some(tn!(stringify!($id))) }
101        }
102        impl $crate::StrictEncode for $ty {
103            fn strict_encode<W: TypedWrite>(&self, mut writer: W) -> io::Result<W> {
104                unsafe {
105                    writer = writer.register_primitive(Primitive::$id);
106                    writer.raw_writer().write_raw_array(self.get().to_le_bytes())?;
107                }
108                Ok(writer)
109            }
110        }
111        impl $crate::StrictDecode for $ty {
112            fn strict_decode(reader: &mut impl TypedRead) -> Result<Self, DecodeError> {
113                let buf =
114                    unsafe { reader.raw_reader().read_raw_array::<{ Self::BITS as usize / 8 }>()? };
115                let v = <$p>::from_le_bytes(buf);
116                Self::new(v).ok_or(DecodeError::ZeroNatural)
117            }
118        }
119    };
120}
121
122macro_rules! encode_float {
123    ($ty:ty, $len:literal, $id:ident) => {
124        #[cfg(feature = "float")]
125        impl $crate::StrictType for $ty {
126            const STRICT_LIB_NAME: &'static str = $crate::LIB_EMBEDDED;
127            fn strict_name() -> Option<TypeName> { Some(tn!(stringify!($id))) }
128        }
129        #[cfg(feature = "float")]
130        impl $crate::StrictEncode for $ty {
131            fn strict_encode<W: TypedWrite>(&self, mut writer: W) -> io::Result<W> {
132                let mut be = [0u8; $len];
133                be.copy_from_slice(&self.to_bits().to_le_bytes()[..$len]);
134                unsafe {
135                    writer = writer.register_primitive(Primitive::$id);
136                    writer.raw_writer().write_raw_array(be)?;
137                }
138                Ok(writer)
139            }
140        }
141        #[cfg(feature = "float")]
142        impl $crate::StrictDecode for $ty {
143            fn strict_decode(reader: &mut impl TypedRead) -> Result<Self, DecodeError> {
144                const BYTES: usize = <$ty>::BITS / 8;
145                let mut inner = [0u8; 32];
146                let buf = unsafe { reader.raw_reader().read_raw_array::<BYTES>()? };
147                inner[..BYTES].copy_from_slice(&buf[..]);
148                let bits = u256::from_le_bytes(inner);
149                Ok(Self::from_bits(bits))
150            }
151        }
152    };
153}
154
155encode_num!(u8, U8);
156encode_num!(u16, U16);
157encode_num!(u24, U24);
158encode_num!(u32, U32);
159encode_num!(u40, U40);
160encode_num!(u48, U48);
161encode_num!(u56, U56);
162encode_num!(u64, U64);
163encode_num!(u128, U128);
164encode_num!(u256, U256);
165encode_num!(u512, U512);
166encode_num!(u1024, U1024);
167
168encode_num!(i8, I8);
169encode_num!(i16, I16);
170encode_num!(i32, I32);
171encode_num!(i64, I64);
172encode_num!(i128, I128);
173encode_num!(i256, I256);
174encode_num!(i512, I512);
175encode_num!(i1024, I1024);
176
177encode_nonzero!(NonZeroU8, u8, N8);
178encode_nonzero!(NonZeroU16, u16, N16);
179encode_nonzero!(NonZeroU32, u32, U32);
180encode_nonzero!(NonZeroU64, u64, U64);
181encode_nonzero!(NonZeroU128, u128, U128);
182
183encode_float!(ieee::Half, 2, F16);
184encode_float!(ieee::Single, 4, F32);
185encode_float!(ieee::Double, 8, F64);
186encode_float!(ieee::X87DoubleExtended, 10, F80);
187encode_float!(ieee::Quad, 16, F128);
188encode_float!(ieee::Oct, 32, F256);
189
190impl<T> StrictType for Box<T>
191where T: StrictType
192{
193    const STRICT_LIB_NAME: &'static str = T::STRICT_LIB_NAME;
194}
195impl<T> StrictSum for Box<T>
196where T: StrictSum
197{
198    const ALL_VARIANTS: &'static [(u8, &'static str)] = T::ALL_VARIANTS;
199    fn variant_name(&self) -> &'static str { self.as_ref().variant_name() }
200}
201impl<T> StrictProduct for Box<T> where T: Default + StrictProduct {}
202impl<T> StrictUnion for Box<T> where T: Default + StrictUnion {}
203impl<T> StrictTuple for Box<T>
204where T: Default + StrictTuple
205{
206    const FIELD_COUNT: u8 = T::FIELD_COUNT;
207}
208impl<T> StrictStruct for Box<T>
209where T: Default + StrictStruct
210{
211    const ALL_FIELDS: &'static [&'static str] = T::ALL_FIELDS;
212}
213impl<T> StrictEncode for Box<T>
214where T: StrictEncode
215{
216    fn strict_encode<W: TypedWrite>(&self, writer: W) -> io::Result<W> {
217        self.as_ref().strict_encode(writer)
218    }
219}
220impl<T> StrictDecode for Box<T>
221where T: StrictDecode
222{
223    fn strict_decode(reader: &mut impl TypedRead) -> Result<Self, DecodeError> {
224        T::strict_decode(reader).map(Box::new)
225    }
226}
227
228impl<T> StrictType for Option<T>
229where T: StrictType
230{
231    const STRICT_LIB_NAME: &'static str = LIB_EMBEDDED;
232    fn strict_name() -> Option<TypeName> { None }
233}
234impl<T> StrictSum for Option<T>
235where T: StrictType
236{
237    const ALL_VARIANTS: &'static [(u8, &'static str)] = &[(0u8, "none"), (1u8, "some")];
238    fn variant_name(&self) -> &'static str {
239        match self {
240            None => "none",
241            Some(_) => "some",
242        }
243    }
244}
245impl<T> StrictUnion for Option<T> where T: StrictType {}
246impl<T: StrictEncode + StrictDumb> StrictEncode for Option<T> {
247    fn strict_encode<W: TypedWrite>(&self, writer: W) -> io::Result<W> {
248        writer.write_union::<Self>(|u| {
249            let u = u.define_unit(vname!("none")).define_newtype::<T>(vname!("some")).complete();
250
251            Ok(match self {
252                None => u.write_unit(vname!("none")),
253                Some(val) => u.write_newtype(vname!("some"), val),
254            }?
255            .complete())
256        })
257    }
258}
259impl<T: StrictDecode> StrictDecode for Option<T> {
260    fn strict_decode(reader: &mut impl TypedRead) -> Result<Self, DecodeError> {
261        reader.read_union(|field_name, u| match field_name.as_str() {
262            "none" => Ok(None),
263            "some" => u.read_tuple(|r| r.read_field().map(Some)),
264            _ => unreachable!("unknown option field"),
265        })
266    }
267}
268
269impl StrictType for () {
270    const STRICT_LIB_NAME: &'static str = LIB_EMBEDDED;
271    fn strict_name() -> Option<TypeName> { None }
272}
273impl StrictEncode for () {
274    fn strict_encode<W: TypedWrite>(&self, writer: W) -> io::Result<W> {
275        Ok(unsafe { writer.register_primitive(Primitive::UNIT) })
276    }
277}
278impl StrictDecode for () {
279    fn strict_decode(_reader: &mut impl TypedRead) -> Result<Self, DecodeError> { Ok(()) }
280}
281
282impl<A: StrictType, B: StrictType> StrictType for (A, B) {
283    const STRICT_LIB_NAME: &'static str = LIB_EMBEDDED;
284    fn strict_name() -> Option<TypeName> { None }
285}
286impl<A: StrictType + Default, B: StrictType + Default> StrictProduct for (A, B) {}
287impl<A: StrictType + Default, B: StrictType + Default> StrictTuple for (A, B) {
288    const FIELD_COUNT: u8 = 2;
289}
290impl<A: StrictEncode + Default, B: StrictEncode + Default> StrictEncode for (A, B) {
291    fn strict_encode<W: TypedWrite>(&self, writer: W) -> io::Result<W> {
292        writer.write_tuple::<Self>(|w| Ok(w.write_field(&self.0)?.write_field(&self.1)?.complete()))
293    }
294}
295impl<A: StrictDecode + Default, B: StrictDecode + Default> StrictDecode for (A, B) {
296    fn strict_decode(reader: &mut impl TypedRead) -> Result<Self, DecodeError> {
297        reader.read_tuple(|r| {
298            let a = r.read_field()?;
299            let b = r.read_field()?;
300            Ok((a, b))
301        })
302    }
303}
304
305impl<A: StrictType, B: StrictType, C: StrictType> StrictType for (A, B, C) {
306    const STRICT_LIB_NAME: &'static str = LIB_EMBEDDED;
307    fn strict_name() -> Option<TypeName> { None }
308}
309impl<A: StrictType + Default, B: StrictType + Default, C: StrictType + Default> StrictProduct
310    for (A, B, C)
311{
312}
313impl<A: StrictType + Default, B: StrictType + Default, C: StrictType + Default> StrictTuple
314    for (A, B, C)
315{
316    const FIELD_COUNT: u8 = 3;
317}
318impl<A: StrictEncode + Default, B: StrictEncode + Default, C: StrictEncode + Default> StrictEncode
319    for (A, B, C)
320{
321    fn strict_encode<W: TypedWrite>(&self, writer: W) -> io::Result<W> {
322        writer.write_tuple::<Self>(|w| {
323            Ok(w.write_field(&self.0)?.write_field(&self.1)?.write_field(&self.2)?.complete())
324        })
325    }
326}
327impl<A: StrictDecode + Default, B: StrictDecode + Default, C: StrictDecode + Default> StrictDecode
328    for (A, B, C)
329{
330    fn strict_decode(reader: &mut impl TypedRead) -> Result<Self, DecodeError> {
331        reader.read_tuple(|r| {
332            let a = r.read_field()?;
333            let b = r.read_field()?;
334            let c = r.read_field()?;
335            Ok((a, b, c))
336        })
337    }
338}
339
340impl<T: StrictType + Copy + StrictDumb, const LEN: usize> StrictType for [T; LEN] {
341    const STRICT_LIB_NAME: &'static str = LIB_EMBEDDED;
342    fn strict_name() -> Option<TypeName> { None }
343}
344impl<T: StrictEncode + Copy + StrictDumb, const LEN: usize> StrictEncode for [T; LEN] {
345    fn strict_encode<W: TypedWrite>(&self, mut writer: W) -> io::Result<W> {
346        for item in self {
347            writer = item.strict_encode(writer)?;
348        }
349        Ok(unsafe {
350            if T::strict_name() == u8::strict_name() {
351                writer.register_array(&Byte::strict_dumb(), LEN as u16)
352            } else {
353                writer.register_array(&T::strict_dumb(), LEN as u16)
354            }
355        })
356    }
357}
358impl<T: StrictDecode + Copy + StrictDumb, const LEN: usize> StrictDecode for [T; LEN] {
359    fn strict_decode(reader: &mut impl TypedRead) -> Result<Self, DecodeError> {
360        let mut ar = [T::strict_dumb(); LEN];
361        for c in ar.iter_mut() {
362            *c = T::strict_decode(reader)?;
363        }
364        Ok(ar)
365    }
366}
367
368impl<T: StrictType + StrictDumb + Copy, const LEN: usize, const REVERSE_STR: bool> StrictType
369    for Array<T, LEN, REVERSE_STR>
370{
371    const STRICT_LIB_NAME: &'static str = LIB_EMBEDDED;
372    fn strict_name() -> Option<TypeName> { None }
373}
374impl<T: StrictEncode + StrictDumb + Copy, const LEN: usize, const REVERSE_STR: bool> StrictEncode
375    for Array<T, LEN, REVERSE_STR>
376{
377    fn strict_encode<W: TypedWrite>(&self, writer: W) -> io::Result<W> {
378        self.as_inner().strict_encode(writer)
379    }
380}
381impl<T: StrictDecode + StrictDumb + Copy, const LEN: usize, const REVERSE_STR: bool> StrictDecode
382    for Array<T, LEN, REVERSE_STR>
383{
384    fn strict_decode(reader: &mut impl TypedRead) -> Result<Self, DecodeError> {
385        <[T; LEN]>::strict_decode(reader).map(Self::from_inner)
386    }
387}
388
389impl<const MIN_LEN: usize, const MAX_LEN: usize> StrictType for Confined<String, MIN_LEN, MAX_LEN> {
390    const STRICT_LIB_NAME: &'static str = LIB_EMBEDDED;
391    fn strict_name() -> Option<TypeName> { None }
392}
393impl<const MIN_LEN: usize, const MAX_LEN: usize> StrictEncode
394    for Confined<String, MIN_LEN, MAX_LEN>
395{
396    fn strict_encode<W: TypedWrite>(&self, writer: W) -> io::Result<W> {
397        unsafe {
398            writer
399                .register_unicode(Sizing::new(MIN_LEN as u64, MAX_LEN as u64))
400                .write_string::<MAX_LEN>(self.as_bytes())
401        }
402    }
403}
404impl<const MIN_LEN: usize, const MAX_LEN: usize> StrictDecode
405    for Confined<String, MIN_LEN, MAX_LEN>
406{
407    fn strict_decode(reader: &mut impl TypedRead) -> Result<Self, DecodeError> {
408        let bytes = unsafe { reader.read_string::<MAX_LEN>()? };
409        let s = String::from_utf8(bytes)?;
410        Confined::try_from(s).map_err(DecodeError::from)
411    }
412}
413
414impl<const MIN_LEN: usize, const MAX_LEN: usize> StrictType
415    for Confined<AsciiString, MIN_LEN, MAX_LEN>
416{
417    const STRICT_LIB_NAME: &'static str = LIB_EMBEDDED;
418    fn strict_name() -> Option<TypeName> { None }
419}
420impl<const MIN_LEN: usize, const MAX_LEN: usize> StrictEncode
421    for Confined<AsciiString, MIN_LEN, MAX_LEN>
422{
423    fn strict_encode<W: TypedWrite>(&self, writer: W) -> io::Result<W> {
424        unsafe {
425            writer
426                .register_list(
427                    &AsciiSym::strict_dumb(),
428                    Sizing::new(MIN_LEN as u64, MAX_LEN as u64),
429                )
430                .write_string::<MAX_LEN>(self.as_bytes())
431        }
432    }
433}
434impl<const MIN_LEN: usize, const MAX_LEN: usize> StrictDecode
435    for Confined<AsciiString, MIN_LEN, MAX_LEN>
436{
437    fn strict_decode(reader: &mut impl TypedRead) -> Result<Self, DecodeError> {
438        let bytes = unsafe { reader.read_string::<MAX_LEN>()? };
439        let s = AsciiString::from_ascii(bytes).map_err(|err| err.ascii_error())?;
440        Confined::try_from(s).map_err(DecodeError::from)
441    }
442}
443
444impl<C1: RestrictedCharSet, C: RestrictedCharSet, const MIN_LEN: usize, const MAX_LEN: usize>
445    StrictType for RString<C1, C, MIN_LEN, MAX_LEN>
446{
447    const STRICT_LIB_NAME: &'static str = LIB_EMBEDDED;
448    fn strict_name() -> Option<TypeName> { None }
449}
450impl<C1: RestrictedCharSet, C: RestrictedCharSet, const MIN_LEN: usize, const MAX_LEN: usize>
451    StrictDumb for RString<C1, C, MIN_LEN, MAX_LEN>
452{
453    fn strict_dumb() -> Self {
454        Self::try_from(format!(
455            "{}{}",
456            C1::strict_dumb(),
457            String::from_utf8(vec![C::strict_dumb().into(); MIN_LEN - 1]).expect("dumb")
458        ))
459        .expect("dumb")
460    }
461}
462impl<C1: RestrictedCharSet, C: RestrictedCharSet, const MIN_LEN: usize, const MAX_LEN: usize>
463    StrictEncode for RString<C1, C, MIN_LEN, MAX_LEN>
464{
465    fn strict_encode<W: TypedWrite>(&self, writer: W) -> io::Result<W> {
466        debug_assert_ne!(
467            MIN_LEN, 0,
468            "Restricted string type can't have minimum length equal to zero"
469        );
470        let sizing = Sizing::new(MIN_LEN as u64, MAX_LEN as u64);
471        unsafe {
472            writer
473                .register_rstring(&C::strict_dumb(), &C1::strict_dumb(), sizing)
474                .write_string::<MAX_LEN>(self.as_bytes())
475        }
476    }
477}
478impl<C1: RestrictedCharSet, C: RestrictedCharSet, const MIN_LEN: usize, const MAX_LEN: usize>
479    StrictDecode for RString<C1, C, MIN_LEN, MAX_LEN>
480{
481    fn strict_decode(reader: &mut impl TypedRead) -> Result<Self, DecodeError> {
482        let bytes = unsafe { reader.read_string::<MAX_LEN>()? };
483        RString::try_from(bytes).map_err(|e| DecodeError::DataIntegrityError(e.to_string()))
484    }
485}
486
487impl<T: StrictType, const MIN_LEN: usize, const MAX_LEN: usize> StrictType
488    for Confined<Vec<T>, MIN_LEN, MAX_LEN>
489{
490    const STRICT_LIB_NAME: &'static str = LIB_EMBEDDED;
491    fn strict_name() -> Option<TypeName> { None }
492}
493impl<T: StrictEncode + StrictDumb, const MIN_LEN: usize, const MAX_LEN: usize> StrictEncode
494    for Confined<Vec<T>, MIN_LEN, MAX_LEN>
495{
496    fn strict_encode<W: TypedWrite>(&self, mut writer: W) -> io::Result<W> {
497        let sizing = Sizing::new(MIN_LEN as u64, MAX_LEN as u64);
498        writer = unsafe {
499            writer = writer.write_collection::<Vec<T>, MIN_LEN, MAX_LEN>(self)?;
500            if T::strict_name() == u8::strict_name() {
501                writer.register_list(&Byte::strict_dumb(), sizing)
502            } else {
503                writer.register_list(&T::strict_dumb(), sizing)
504            }
505        };
506        Ok(writer)
507    }
508}
509impl<T: StrictDecode, const MIN_LEN: usize, const MAX_LEN: usize> StrictDecode
510    for Confined<Vec<T>, MIN_LEN, MAX_LEN>
511{
512    fn strict_decode(reader: &mut impl TypedRead) -> Result<Self, DecodeError> {
513        let len = unsafe { reader.raw_reader().read_raw_len::<MAX_LEN>()? };
514        let mut col = Vec::<T>::with_capacity(len);
515        for _ in 0..len {
516            col.push(StrictDecode::strict_decode(reader)?);
517        }
518        Confined::try_from(col).map_err(DecodeError::from)
519    }
520}
521
522impl<T: StrictType, const MIN_LEN: usize, const MAX_LEN: usize> StrictType
523    for Confined<VecDeque<T>, MIN_LEN, MAX_LEN>
524{
525    const STRICT_LIB_NAME: &'static str = LIB_EMBEDDED;
526    fn strict_name() -> Option<TypeName> { None }
527}
528impl<T: StrictEncode + StrictDumb, const MIN_LEN: usize, const MAX_LEN: usize> StrictEncode
529    for Confined<VecDeque<T>, MIN_LEN, MAX_LEN>
530{
531    fn strict_encode<W: TypedWrite>(&self, mut writer: W) -> io::Result<W> {
532        let sizing = Sizing::new(MIN_LEN as u64, MAX_LEN as u64);
533        writer = unsafe {
534            writer = writer.write_collection::<VecDeque<T>, MIN_LEN, MAX_LEN>(self)?;
535            if T::strict_name() == u8::strict_name() {
536                writer.register_list(&Byte::strict_dumb(), sizing)
537            } else {
538                writer.register_list(&T::strict_dumb(), sizing)
539            }
540        };
541        Ok(writer)
542    }
543}
544impl<T: StrictDecode, const MIN_LEN: usize, const MAX_LEN: usize> StrictDecode
545    for Confined<VecDeque<T>, MIN_LEN, MAX_LEN>
546{
547    fn strict_decode(reader: &mut impl TypedRead) -> Result<Self, DecodeError> {
548        let len = unsafe { reader.raw_reader().read_raw_len::<MAX_LEN>()? };
549        let mut col = VecDeque::<T>::with_capacity(len);
550        for _ in 0..len {
551            col.push_back(StrictDecode::strict_decode(reader)?);
552        }
553        Confined::try_from(col).map_err(DecodeError::from)
554    }
555}
556
557impl<T: StrictType + Ord, const MIN_LEN: usize, const MAX_LEN: usize> StrictType
558    for Confined<BTreeSet<T>, MIN_LEN, MAX_LEN>
559{
560    const STRICT_LIB_NAME: &'static str = LIB_EMBEDDED;
561    fn strict_name() -> Option<TypeName> { None }
562}
563impl<T: StrictEncode + Ord + StrictDumb, const MIN_LEN: usize, const MAX_LEN: usize> StrictEncode
564    for Confined<BTreeSet<T>, MIN_LEN, MAX_LEN>
565{
566    fn strict_encode<W: TypedWrite>(&self, mut writer: W) -> io::Result<W> {
567        unsafe {
568            writer = writer.write_collection::<BTreeSet<T>, MIN_LEN, MAX_LEN>(self)?;
569        }
570        Ok(unsafe {
571            writer.register_set(&T::strict_dumb(), Sizing::new(MIN_LEN as u64, MAX_LEN as u64))
572        })
573    }
574}
575impl<T: StrictDecode + Ord, const MIN_LEN: usize, const MAX_LEN: usize> StrictDecode
576    for Confined<BTreeSet<T>, MIN_LEN, MAX_LEN>
577{
578    fn strict_decode(reader: &mut impl TypedRead) -> Result<Self, DecodeError> {
579        let len = unsafe { reader.raw_reader().read_raw_len::<MAX_LEN>()? };
580        let mut col = BTreeSet::<T>::new();
581        for _ in 0..len {
582            let item = StrictDecode::strict_decode(reader)?;
583            if matches!(col.last(), Some(last) if last > &item) {
584                return Err(DecodeError::BrokenSetOrder);
585            }
586            if !col.insert(item) {
587                return Err(DecodeError::RepeatedSetValue);
588            }
589        }
590        Confined::try_from(col).map_err(DecodeError::from)
591    }
592}
593
594impl<K: StrictType + Ord + Hash, V: StrictType, const MIN_LEN: usize, const MAX_LEN: usize>
595    StrictType for Confined<BTreeMap<K, V>, MIN_LEN, MAX_LEN>
596{
597    const STRICT_LIB_NAME: &'static str = LIB_EMBEDDED;
598    fn strict_name() -> Option<TypeName> { None }
599}
600impl<
601        K: StrictEncode + Ord + Hash + StrictDumb,
602        V: StrictEncode + StrictDumb,
603        const MIN_LEN: usize,
604        const MAX_LEN: usize,
605    > StrictEncode for Confined<BTreeMap<K, V>, MIN_LEN, MAX_LEN>
606{
607    fn strict_encode<W: TypedWrite>(&self, mut writer: W) -> io::Result<W> {
608        unsafe {
609            writer.raw_writer().write_raw_len::<MAX_LEN>(self.len())?;
610        }
611        for (k, v) in self {
612            writer = k.strict_encode(writer)?;
613            writer = v.strict_encode(writer)?
614        }
615        Ok(unsafe {
616            writer.register_map(
617                &K::strict_dumb(),
618                &V::strict_dumb(),
619                Sizing::new(MIN_LEN as u64, MAX_LEN as u64),
620            )
621        })
622    }
623}
624impl<
625        K: StrictDecode + Ord + Hash + StrictDumb,
626        V: StrictDecode + StrictDumb,
627        const MIN_LEN: usize,
628        const MAX_LEN: usize,
629    > StrictDecode for Confined<BTreeMap<K, V>, MIN_LEN, MAX_LEN>
630{
631    fn strict_decode(reader: &mut impl TypedRead) -> Result<Self, DecodeError> {
632        let len = unsafe { reader.raw_reader().read_raw_len::<MAX_LEN>()? };
633        let mut col = BTreeMap::new();
634        for _ in 0..len {
635            let key = StrictDecode::strict_decode(reader)?;
636            let val = StrictDecode::strict_decode(reader)?;
637            if matches!(col.last_key_value(), Some((last, _)) if last > &key) {
638                return Err(DecodeError::BrokenMapOrder);
639            }
640            if col.insert(key, val).is_some() {
641                return Err(DecodeError::RepeatedMapValue);
642            }
643        }
644        Confined::try_from(col).map_err(DecodeError::from)
645    }
646}