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}