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