facet_msgpack/
from_msgpack.rs

1use crate::constants::*;
2use crate::errors::Error as DecodeError;
3
4use facet_core::{Facet, Opaque};
5use facet_reflect::PokeUninit;
6use log::trace;
7
8/// Deserializes MessagePack-encoded data into a type that implements `Facet`.
9///
10/// # Example
11/// ```
12/// use facet::Facet;
13/// use facet_msgpack::from_str;
14///
15/// #[derive(Debug, Facet, PartialEq)]
16/// struct User {
17///     id: u64,
18///     username: String,
19/// }
20///
21/// // MessagePack binary data (equivalent to {"id": 42, "username": "user123"})
22/// let msgpack_data = [
23///     0x82, 0xa2, 0x69, 0x64, 0x2a, 0xa8, 0x75, 0x73,
24///     0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0xa7, 0x75,
25///     0x73, 0x65, 0x72, 0x31, 0x32, 0x33
26/// ];
27///
28/// let user: User = from_str(&msgpack_data).unwrap();
29/// assert_eq!(user, User { id: 42, username: "user123".to_string() });
30/// ```
31pub fn from_str<T: Facet>(msgpack: &[u8]) -> Result<T, DecodeError> {
32    // Allocate a Poke for type T
33    let (poke, _guard) = PokeUninit::alloc::<T>();
34
35    // Deserialize the MessagePack into the Poke
36    let opaque = from_slice_opaque(poke, msgpack)?;
37
38    // Convert the Opaque to the concrete type T
39    let result = unsafe { opaque.read::<T>() };
40
41    Ok(result)
42}
43
44/// Deserializes MessagePack-encoded data into a Facet Partial.
45///
46/// This function takes a MessagePack byte array and populates a Partial object
47/// according to the shape description provided by the Partial.
48///
49/// # Example
50///
51/// ```
52/// use facet::Facet;
53/// use facet_msgpack::from_str;
54///
55/// #[derive(Debug, Facet, PartialEq)]
56/// struct User {
57///     id: u64,
58///     username: String,
59/// }
60///
61/// // MessagePack binary data (equivalent to {"id": 42, "username": "user123"})
62/// let msgpack_data = [
63///     0x82, 0xa2, 0x69, 0x64, 0x2a, 0xa8, 0x75, 0x73,
64///     0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0xa7, 0x75,
65///     0x73, 0x65, 0x72, 0x31, 0x32, 0x33
66/// ];
67///
68/// let user: User = from_str(&msgpack_data).unwrap();
69/// assert_eq!(user, User { id: 42, username: "user123".to_string() });
70/// ```
71///
72/// # Parameters
73/// * `partial` - A mutable reference to a Partial object that will be filled with deserialized data
74/// * `msgpack` - A byte slice containing MessagePack-encoded data
75///
76/// # Returns
77/// * `Ok(())` if deserialization was successful
78/// * `Err(DecodeError)` if an error occurred during deserialization
79///
80/// # MessagePack Format
81/// This implementation follows the MessagePack specification:
82/// <https://github.com/msgpack/msgpack/blob/master/spec.md>
83#[allow(clippy::needless_lifetimes)]
84pub fn from_slice_opaque<'mem>(
85    poke: PokeUninit<'mem>,
86    msgpack: &[u8],
87) -> Result<Opaque<'mem>, DecodeError> {
88    let mut decoder = Decoder::new(msgpack);
89
90    fn deserialize_value<'mem>(
91        decoder: &mut Decoder,
92        poke: PokeUninit<'mem>,
93    ) -> Result<Opaque<'mem>, DecodeError> {
94        let shape = poke.shape();
95        trace!("Deserializing {:?}", shape);
96
97        let opaque = match poke {
98            PokeUninit::Scalar(pv) => {
99                trace!("Deserializing scalar");
100                if pv.shape().is_type::<String>() {
101                    let s = decoder.decode_string()?;
102                    let data = pv.put(s);
103                    data
104                } else if pv.shape().is_type::<u64>() {
105                    let n = decoder.decode_u64()?;
106                    pv.put(n)
107                } else {
108                    todo!("Unsupported scalar type: {}", pv.shape())
109                }
110            }
111            PokeUninit::Struct(mut ps) => {
112                trace!("Deserializing struct");
113                let map_len = decoder.decode_map_len()?;
114
115                for _ in 0..map_len {
116                    let key = decoder.decode_string()?;
117                    let (index, field_poke) = ps
118                        .field_by_name(&key)
119                        .map_err(|_| DecodeError::UnknownField(key))?;
120
121                    deserialize_value(decoder, field_poke)?;
122                    unsafe { ps.mark_initialized(index) };
123                }
124                ps.build_in_place()
125            }
126            _ => {
127                todo!("Unsupported shape: {:?}", shape)
128            }
129        };
130
131        Ok(opaque)
132    }
133
134    deserialize_value(&mut decoder, poke)
135}
136
137struct Decoder<'input> {
138    input: &'input [u8],
139    offset: usize,
140}
141
142impl<'input> Decoder<'input> {
143    fn new(input: &'input [u8]) -> Self {
144        Decoder { input, offset: 0 }
145    }
146
147    /// Decodes a single byte from the input.
148    /// This is a low-level method used by other decoders.
149    fn decode_u8(&mut self) -> Result<u8, DecodeError> {
150        if self.offset >= self.input.len() {
151            return Err(DecodeError::InsufficientData);
152        }
153        let value = self.input[self.offset];
154        self.offset += 1;
155        Ok(value)
156    }
157
158    /// Decodes a 16-bit unsigned integer in big-endian byte order.
159    /// This is a low-level method used by other decoders.
160    fn decode_u16(&mut self) -> Result<u16, DecodeError> {
161        if self.offset + 2 > self.input.len() {
162            return Err(DecodeError::InsufficientData);
163        }
164        let value =
165            u16::from_be_bytes(self.input[self.offset..self.offset + 2].try_into().unwrap());
166        self.offset += 2;
167        Ok(value)
168    }
169
170    /// Decodes a 32-bit unsigned integer in big-endian byte order.
171    /// This is a low-level method used by other decoders.
172    fn decode_u32(&mut self) -> Result<u32, DecodeError> {
173        if self.offset + 4 > self.input.len() {
174            return Err(DecodeError::InsufficientData);
175        }
176        let value =
177            u32::from_be_bytes(self.input[self.offset..self.offset + 4].try_into().unwrap());
178        self.offset += 4;
179        Ok(value)
180    }
181
182    /// Decodes a MessagePack-encoded unsigned 64-bit integer.
183    /// Handles the following MessagePack types:
184    /// - positive fixint (0x00 - 0x7f): single-byte positive integer
185    /// - uint8 (0xcc): 8-bit unsigned integer
186    /// - uint16 (0xcd): 16-bit unsigned integer (big-endian)
187    /// - uint32 (0xce): 32-bit unsigned integer (big-endian)
188    /// - uint64 (0xcf): 64-bit unsigned integer (big-endian)
189    ///
190    /// Ref: <https://github.com/msgpack/msgpack/blob/master/spec.md#int-format-family>
191    fn decode_u64(&mut self) -> Result<u64, DecodeError> {
192        match self.decode_u8()? {
193            MSGPACK_UINT8 => Ok(self.decode_u8()? as u64),
194            MSGPACK_UINT16 => Ok(self.decode_u16()? as u64),
195            MSGPACK_UINT32 => Ok(self.decode_u32()? as u64),
196            MSGPACK_UINT64 => {
197                if self.offset + 8 > self.input.len() {
198                    return Err(DecodeError::InsufficientData);
199                }
200                let value = u64::from_be_bytes(
201                    self.input[self.offset..self.offset + 8].try_into().unwrap(),
202                );
203                self.offset += 8;
204                Ok(value)
205            }
206            prefix @ MSGPACK_POSFIXINT_MIN..=MSGPACK_POSFIXINT_MAX => Ok(prefix as u64),
207            _ => Err(DecodeError::UnexpectedType),
208        }
209    }
210
211    /// Decodes a MessagePack-encoded string.
212    /// Handles the following MessagePack types:
213    /// - fixstr (0xa0 - 0xbf): string up to 31 bytes
214    /// - str8 (0xd9): string up to 255 bytes
215    /// - str16 (0xda): string up to 65535 bytes
216    /// - str32 (0xdb): string up to 4294967295 bytes
217    ///
218    /// Ref: <https://github.com/msgpack/msgpack/blob/master/spec.md#formats-str>
219    fn decode_string(&mut self) -> Result<String, DecodeError> {
220        let prefix = self.decode_u8()?;
221
222        let len = match prefix {
223            prefix @ MSGPACK_FIXSTR_MIN..=MSGPACK_FIXSTR_MAX => (prefix & 0x1f) as usize,
224            MSGPACK_STR8 => self.decode_u8()? as usize,
225            MSGPACK_STR16 => self.decode_u16()? as usize,
226            MSGPACK_STR32 => self.decode_u32()? as usize,
227            _ => return Err(DecodeError::UnexpectedType),
228        };
229
230        if self.offset + len > self.input.len() {
231            return Err(DecodeError::InsufficientData);
232        }
233
234        let value = String::from_utf8(self.input[self.offset..self.offset + len].to_vec())
235            .map_err(|_| DecodeError::InvalidData)?;
236        self.offset += len;
237        Ok(value)
238    }
239
240    /// Decodes a MessagePack-encoded map length.
241    /// Handles the following MessagePack types:
242    /// - fixmap (0x80 - 0x8f): map with up to 15 elements
243    /// - map16 (0xde): map with up to 65535 elements
244    /// - map32 (0xdf): map with up to 4294967295 elements
245    ///
246    /// Ref: <https://github.com/msgpack/msgpack/blob/master/spec.md#formats-map>
247    fn decode_map_len(&mut self) -> Result<usize, DecodeError> {
248        let prefix = self.decode_u8()?;
249
250        match prefix {
251            prefix @ MSGPACK_FIXMAP_MIN..=MSGPACK_FIXMAP_MAX => Ok((prefix & 0x0f) as usize),
252            MSGPACK_MAP16 => Ok(self.decode_u16()? as usize),
253            MSGPACK_MAP32 => Ok(self.decode_u32()? as usize),
254            _ => Err(DecodeError::UnexpectedType),
255        }
256    }
257}