Skip to main content

midnight_serialize/
deserializable.rs

1// This file is part of midnight-ledger.
2// Copyright (C) Midnight Foundation
3// SPDX-License-Identifier: Apache-2.0
4// Licensed under the Apache License, Version 2.0 (the "License");
5// You may not use this file except in compliance with the License.
6// You may obtain a copy of the License at
7// http://www.apache.org/licenses/LICENSE-2.0
8// Unless required by applicable law or agreed to in writing, software
9// distributed under the License is distributed on an "AS IS" BASIS,
10// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11// See the License for the specific language governing permissions and
12// limitations under the License.
13
14use crate::VecExt;
15use crate::serializable::GLOBAL_TAG;
16use crate::tagged::Tagged;
17use std::borrow::Cow;
18use std::io::{BufRead, Read};
19use std::marker::PhantomData;
20use std::sync::Arc;
21use std::{collections::HashMap, collections::HashSet, hash::Hash};
22
23#[cfg(debug_assertions)]
24pub const RECURSION_LIMIT: u32 = 50;
25#[cfg(not(debug_assertions))]
26pub const RECURSION_LIMIT: u32 = 250;
27
28// Top-level deserialization function
29pub fn tagged_deserialize<T: Deserializable + Tagged>(reader: impl Read) -> std::io::Result<T> {
30    tagged_deserialize_inner(reader, true)
31}
32
33pub fn tagged_deserialize_sequence<T: Deserializable + Tagged>(
34    mut reader: impl BufRead,
35) -> std::io::Result<Vec<T>> {
36    let mut res = vec![];
37    while !reader.fill_buf()?.is_empty() {
38        res.push(tagged_deserialize_inner(&mut reader, false)?);
39    }
40    Ok(res)
41}
42
43fn tagged_deserialize_inner<T: Deserializable + Tagged>(
44    mut reader: impl Read,
45    ensure_consumed: bool,
46) -> std::io::Result<T> {
47    let tag_expected = format!("{GLOBAL_TAG}{}:", T::tag());
48    let mut read_tag = vec![0u8; tag_expected.len()];
49    let mut remaining_tag_buf = &mut read_tag[..];
50    while !remaining_tag_buf.is_empty() {
51        let read = reader.read(remaining_tag_buf)?;
52        if read == 0 {
53            let rem = remaining_tag_buf.len();
54            let len = read_tag.len() - rem;
55            read_tag.truncate(len);
56            break;
57        }
58        remaining_tag_buf = &mut remaining_tag_buf[read..];
59    }
60    if read_tag != tag_expected.as_bytes() {
61        let sanitised = String::from_utf8_lossy(&read_tag).replace(
62            |c: char| -> bool { !c.is_ascii_alphanumeric() && !":_-()[],".contains(c) },
63            "�",
64        );
65        return Err(std::io::Error::new(
66            std::io::ErrorKind::InvalidData,
67            format!("expected header tag '{tag_expected}', got '{sanitised}'"),
68        ));
69    }
70    let value = <T as Deserializable>::deserialize(&mut reader, 0)?;
71
72    if !ensure_consumed {
73        return Ok(value);
74    }
75
76    #[allow(clippy::unbuffered_bytes)] // we can permit a potentally inefficient count here, as in
77    let count = reader.bytes().count(); // the happy path it should be 0
78
79    if count == 0 {
80        return Ok(value);
81    }
82
83    Err(std::io::Error::new(
84        std::io::ErrorKind::InvalidData,
85        format!(
86            "Not all bytes read deserializing '{}'; {} bytes remaining",
87            tag_expected, count
88        ),
89    ))
90}
91
92pub trait Deserializable
93where
94    Self: Sized,
95{
96    const LIMIT_RECURSION: bool = true;
97
98    fn deserialize(reader: &mut impl Read, recursion_depth: u32) -> std::io::Result<Self>;
99
100    fn check_rec(depth: &mut u32) -> std::io::Result<()> {
101        if Self::LIMIT_RECURSION {
102            *depth += 1;
103            if *depth > RECURSION_LIMIT {
104                return Err(std::io::Error::new(
105                    std::io::ErrorKind::InvalidData,
106                    "exceeded recursion depth deserializing",
107                ));
108            }
109        }
110        Ok(())
111    }
112}
113
114impl<T: Deserializable> Deserializable for Vec<T> {
115    fn deserialize(reader: &mut impl Read, mut recursion_depth: u32) -> std::io::Result<Self> {
116        Self::check_rec(&mut recursion_depth)?;
117        let len = <u32 as Deserializable>::deserialize(reader, recursion_depth)?;
118        let mut result = Vec::with_bounded_capacity(len as usize);
119        for _ in 0..len {
120            result.push(<T as Deserializable>::deserialize(reader, recursion_depth)?);
121        }
122        Ok(result)
123    }
124}
125
126impl<K: Deserializable + PartialOrd + Hash + Eq, V: Deserializable> Deserializable
127    for HashMap<K, V>
128{
129    fn deserialize(reader: &mut impl Read, mut recursion_depth: u32) -> std::io::Result<Self> {
130        Self::check_rec(&mut recursion_depth)?;
131        let len = <u32 as Deserializable>::deserialize(reader, recursion_depth)?;
132        let mut result = HashMap::new();
133        for _ in 0..len {
134            let k = <K as Deserializable>::deserialize(reader, recursion_depth)?;
135            let v = <V as Deserializable>::deserialize(reader, recursion_depth)?;
136            result.insert(k, v);
137        }
138        Ok(result)
139    }
140}
141
142impl<T: Deserializable + Hash + Eq> Deserializable for HashSet<T> {
143    fn deserialize(reader: &mut impl Read, mut recursion_depth: u32) -> std::io::Result<Self> {
144        Self::check_rec(&mut recursion_depth)?;
145        let len = <u32 as Deserializable>::deserialize(reader, recursion_depth)?;
146        let mut result = HashSet::new();
147        for _ in 0..len {
148            result.insert(<T as Deserializable>::deserialize(reader, recursion_depth)?);
149        }
150        Ok(result)
151    }
152}
153
154impl<T: Deserializable> Deserializable for Option<T> {
155    fn deserialize(reader: &mut impl Read, mut recursion_depth: u32) -> std::io::Result<Self> {
156        Self::check_rec(&mut recursion_depth)?;
157        let some = <u8 as Deserializable>::deserialize(reader, recursion_depth)?;
158        match some {
159            0 => Ok(None),
160            1 => Ok(Some(<T as Deserializable>::deserialize(
161                reader,
162                recursion_depth,
163            )?)),
164            _ => Err(std::io::Error::new(
165                std::io::ErrorKind::InvalidData,
166                format!("Invalid discriminant: {}.", some),
167            )),
168        }
169    }
170}
171
172impl<T: Deserializable> Deserializable for Arc<T> {
173    fn deserialize(
174        reader: &mut impl Read,
175        mut recursion_depth: u32,
176    ) -> Result<Self, std::io::Error> {
177        Self::check_rec(&mut recursion_depth)?;
178        Ok(Arc::new(T::deserialize(reader, recursion_depth)?))
179    }
180}
181
182impl<const N: usize> Deserializable for [u8; N] {
183    fn deserialize(reader: &mut impl Read, _recursion_depth: u32) -> std::io::Result<Self> {
184        let mut res = [0u8; N];
185        reader.read_exact(&mut res[..])?;
186        Ok(res)
187    }
188}
189
190impl<T: ?Sized> Deserializable for PhantomData<T> {
191    fn deserialize(_reader: &mut impl Read, _recursion_depth: u32) -> std::io::Result<Self> {
192        Ok(PhantomData)
193    }
194}
195
196impl<T: Deserializable> Deserializable for Box<T> {
197    fn deserialize(reader: &mut impl Read, recursion_depth: u32) -> std::io::Result<Self> {
198        T::deserialize(reader, recursion_depth).map(Box::new)
199    }
200}
201
202impl<'a, T: ToOwned + ?Sized> Deserializable for Cow<'a, T>
203where
204    T::Owned: Deserializable,
205{
206    fn deserialize(reader: &mut impl Read, recursion_depth: u32) -> std::io::Result<Self> {
207        <T::Owned>::deserialize(reader, recursion_depth).map(Cow::Owned)
208    }
209}