shapely_urlencoded/
lib.rs1#![warn(missing_docs)]
2#![doc = include_str!("../README.md")]
3
4use shapely::{Partial, error, trace, warn};
5
6#[cfg(test)]
7mod tests;
8
9pub fn from_urlencoded(partial: &mut Partial, input: &str) -> Result<(), UrlEncodedError> {
32 use shapely::{Innards, Scalar};
33
34 trace!("Starting URL encoded form data deserialization");
35
36 let pairs = form_urlencoded::parse(input.as_bytes());
38
39 let mut pairs_map: std::collections::HashMap<String, String> = std::collections::HashMap::new();
41 for (key, value) in pairs {
42 pairs_map.insert(key.to_string(), value.to_string());
43 }
44
45 let shape_desc = partial.shape();
47 let shape = shape_desc.get();
48 trace!("Deserializing value with shape:\n{:?}", shape);
49
50 match &shape.innards {
51 Innards::Struct { .. } => {
52 trace!("Deserializing \x1b[1;36mstruct\x1b[0m");
53
54 for (key, value) in pairs_map {
55 trace!("Processing field key: \x1b[1;33m{}\x1b[0m", key);
56
57 let slot = match partial.slot_by_name(&key) {
58 Ok(slot) => slot,
59 Err(_) => {
60 warn!("Unknown field: {}", key);
61 continue; }
63 };
64
65 let slot_shape = slot.shape();
66 let slot_shape_ref = slot_shape.get();
67
68 match &slot_shape_ref.innards {
69 Innards::Scalar(scalar) => {
70 let mut partial_field = Partial::alloc(slot.shape());
71 let field_slot = partial_field.scalar_slot().expect("Scalar slot");
72
73 match scalar {
74 Scalar::String => {
75 field_slot.fill(value);
76 }
77 Scalar::U64 => match value.parse::<u64>() {
78 Ok(num) => field_slot.fill(num),
79 Err(_) => {
80 return Err(UrlEncodedError::InvalidNumber(key.clone(), value));
81 }
82 },
83 _ => {
85 warn!("Unsupported scalar type: {:?}", scalar);
86 return Err(UrlEncodedError::UnsupportedType(format!(
87 "{:?}",
88 scalar
89 )));
90 }
91 }
92
93 slot.fill_from_partial(partial_field);
94 }
95 _ => {
97 error!("Unsupported shape: {:?}", slot_shape_ref.innards);
98 return Err(UrlEncodedError::UnsupportedShape(format!(
99 "{:?}",
100 slot_shape_ref.innards
101 )));
102 }
103 }
104 }
105
106 trace!("Finished deserializing \x1b[1;36mstruct\x1b[0m");
107 }
108 _ => {
109 error!("Unsupported shape: {:?}", shape.innards);
110 return Err(UrlEncodedError::UnsupportedShape(format!(
111 "{:?}",
112 shape.innards
113 )));
114 }
115 }
116
117 trace!(
118 "Successfully deserialized URL encoded form data for shape: \x1b[1;32m{}\x1b[0m at address \x1b[1;34m{:?}\x1b[0m\n",
119 shape,
120 partial.addr()
121 );
122 Ok(())
123}
124
125#[derive(Debug)]
127pub enum UrlEncodedError {
128 InvalidNumber(String, String),
130 UnsupportedShape(String),
132 UnsupportedType(String),
134}
135
136impl std::fmt::Display for UrlEncodedError {
137 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
138 match self {
139 UrlEncodedError::InvalidNumber(field, value) => {
140 write!(f, "Invalid number for field '{}': '{}'", field, value)
141 }
142 UrlEncodedError::UnsupportedShape(shape) => {
143 write!(f, "Unsupported shape: {}", shape)
144 }
145 UrlEncodedError::UnsupportedType(ty) => {
146 write!(f, "Unsupported type: {}", ty)
147 }
148 }
149 }
150}
151
152impl std::error::Error for UrlEncodedError {}