facet_msgpack/
from_msgpack.rs

1use crate::constants::*;
2use crate::errors::Error as DecodeError;
3use facet_core::ShapeExt as _;
4use facet_core::{Facet, Opaque, OpaqueConst};
5use facet_poke::Poke;
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) = Poke::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: Poke<'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: Poke<'mem>,
93    ) -> Result<Opaque<'mem>, DecodeError> {
94        let shape = poke.shape();
95        trace!("Deserializing {:?}", shape);
96
97        let opaque = match poke {
98            Poke::Scalar(pv) => {
99                trace!("Deserializing scalar");
100                if pv.shape().is_type::<String>() {
101                    let s = decoder.decode_string()?;
102                    let data = unsafe { pv.put(OpaqueConst::new(&s)) };
103                    core::mem::forget(s);
104                    data
105                } else if pv.shape().is_type::<u64>() {
106                    let n = decoder.decode_u64()?;
107                    unsafe { pv.put(OpaqueConst::new(&n)) }
108                } else {
109                    todo!("Unsupported scalar type: {}", pv.shape())
110                }
111            }
112            Poke::Struct(mut ps) => {
113                trace!("Deserializing struct");
114                let map_len = decoder.decode_map_len()?;
115
116                for _ in 0..map_len {
117                    let key = decoder.decode_string()?;
118                    let (index, field_poke) = ps
119                        .field_by_name(&key)
120                        .map_err(|_| DecodeError::UnknownField(key))?;
121
122                    deserialize_value(decoder, field_poke)?;
123                    unsafe { ps.mark_initialized(index) };
124                }
125                ps.build_in_place()
126            }
127            _ => {
128                todo!("Unsupported shape: {:?}", shape)
129            }
130        };
131
132        Ok(opaque)
133    }
134
135    deserialize_value(&mut decoder, poke)
136}
137
138struct Decoder<'input> {
139    input: &'input [u8],
140    offset: usize,
141}
142
143impl<'input> Decoder<'input> {
144    fn new(input: &'input [u8]) -> Self {
145        Decoder { input, offset: 0 }
146    }
147
148    /// Decodes a single byte from the input.
149    /// This is a low-level method used by other decoders.
150    fn decode_u8(&mut self) -> Result<u8, DecodeError> {
151        if self.offset >= self.input.len() {
152            return Err(DecodeError::InsufficientData);
153        }
154        let value = self.input[self.offset];
155        self.offset += 1;
156        Ok(value)
157    }
158
159    /// Decodes a 16-bit unsigned integer in big-endian byte order.
160    /// This is a low-level method used by other decoders.
161    fn decode_u16(&mut self) -> Result<u16, DecodeError> {
162        if self.offset + 2 > self.input.len() {
163            return Err(DecodeError::InsufficientData);
164        }
165        let value =
166            u16::from_be_bytes(self.input[self.offset..self.offset + 2].try_into().unwrap());
167        self.offset += 2;
168        Ok(value)
169    }
170
171    /// Decodes a 32-bit unsigned integer in big-endian byte order.
172    /// This is a low-level method used by other decoders.
173    fn decode_u32(&mut self) -> Result<u32, DecodeError> {
174        if self.offset + 4 > self.input.len() {
175            return Err(DecodeError::InsufficientData);
176        }
177        let value =
178            u32::from_be_bytes(self.input[self.offset..self.offset + 4].try_into().unwrap());
179        self.offset += 4;
180        Ok(value)
181    }
182
183    /// Decodes a MessagePack-encoded unsigned 64-bit integer.
184    /// Handles the following MessagePack types:
185    /// - positive fixint (0x00 - 0x7f): single-byte positive integer
186    /// - uint8 (0xcc): 8-bit unsigned integer
187    /// - uint16 (0xcd): 16-bit unsigned integer (big-endian)
188    /// - uint32 (0xce): 32-bit unsigned integer (big-endian)
189    /// - uint64 (0xcf): 64-bit unsigned integer (big-endian)
190    ///
191    /// Ref: <https://github.com/msgpack/msgpack/blob/master/spec.md#int-format-family>
192    fn decode_u64(&mut self) -> Result<u64, DecodeError> {
193        match self.decode_u8()? {
194            MSGPACK_UINT8 => Ok(self.decode_u8()? as u64),
195            MSGPACK_UINT16 => Ok(self.decode_u16()? as u64),
196            MSGPACK_UINT32 => Ok(self.decode_u32()? as u64),
197            MSGPACK_UINT64 => {
198                if self.offset + 8 > self.input.len() {
199                    return Err(DecodeError::InsufficientData);
200                }
201                let value = u64::from_be_bytes(
202                    self.input[self.offset..self.offset + 8].try_into().unwrap(),
203                );
204                self.offset += 8;
205                Ok(value)
206            }
207            prefix @ MSGPACK_POSFIXINT_MIN..=MSGPACK_POSFIXINT_MAX => Ok(prefix as u64),
208            _ => Err(DecodeError::UnexpectedType),
209        }
210    }
211
212    /// Decodes a MessagePack-encoded string.
213    /// Handles the following MessagePack types:
214    /// - fixstr (0xa0 - 0xbf): string up to 31 bytes
215    /// - str8 (0xd9): string up to 255 bytes
216    /// - str16 (0xda): string up to 65535 bytes
217    /// - str32 (0xdb): string up to 4294967295 bytes
218    ///
219    /// Ref: <https://github.com/msgpack/msgpack/blob/master/spec.md#formats-str>
220    fn decode_string(&mut self) -> Result<String, DecodeError> {
221        let prefix = self.decode_u8()?;
222
223        let len = match prefix {
224            prefix @ MSGPACK_FIXSTR_MIN..=MSGPACK_FIXSTR_MAX => (prefix & 0x1f) as usize,
225            MSGPACK_STR8 => self.decode_u8()? as usize,
226            MSGPACK_STR16 => self.decode_u16()? as usize,
227            MSGPACK_STR32 => self.decode_u32()? as usize,
228            _ => return Err(DecodeError::UnexpectedType),
229        };
230
231        if self.offset + len > self.input.len() {
232            return Err(DecodeError::InsufficientData);
233        }
234
235        let value = String::from_utf8(self.input[self.offset..self.offset + len].to_vec())
236            .map_err(|_| DecodeError::InvalidData)?;
237        self.offset += len;
238        Ok(value)
239    }
240
241    /// Decodes a MessagePack-encoded map length.
242    /// Handles the following MessagePack types:
243    /// - fixmap (0x80 - 0x8f): map with up to 15 elements
244    /// - map16 (0xde): map with up to 65535 elements
245    /// - map32 (0xdf): map with up to 4294967295 elements
246    ///
247    /// Ref: <https://github.com/msgpack/msgpack/blob/master/spec.md#formats-map>
248    fn decode_map_len(&mut self) -> Result<usize, DecodeError> {
249        let prefix = self.decode_u8()?;
250
251        match prefix {
252            prefix @ MSGPACK_FIXMAP_MIN..=MSGPACK_FIXMAP_MAX => Ok((prefix & 0x0f) as usize),
253            MSGPACK_MAP16 => Ok(self.decode_u16()? as usize),
254            MSGPACK_MAP32 => Ok(self.decode_u32()? as usize),
255            _ => Err(DecodeError::UnexpectedType),
256        }
257    }
258}