1use serde::ser::{self, Impossible, Serialize};
13use std::fmt;
14
15pub(crate) fn to_form<T: Serialize + ?Sized>(value: &T) -> Result<String, Error> {
17 let mut out = form_urlencoded::Serializer::new(String::new());
18 value.serialize(TopSerializer { out: &mut out })?;
19 Ok(out.finish())
20}
21
22pub fn as_json<T: Serialize, S: ser::Serializer>(
29 value: &T,
30 serializer: S,
31) -> Result<S::Ok, S::Error> {
32 let json = serde_json::to_string(value).map_err(ser::Error::custom)?;
33 serializer.serialize_str(&json)
34}
35
36#[derive(Debug)]
37pub(crate) enum Error {
38 NotScalar,
40 Custom(String),
41}
42
43impl fmt::Display for Error {
44 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
45 match self {
46 Error::NotScalar => f.write_str("value is not a scalar"),
47 Error::Custom(msg) => f.write_str(msg),
48 }
49 }
50}
51
52impl std::error::Error for Error {}
53
54impl ser::Error for Error {
55 fn custom<T: fmt::Display>(msg: T) -> Self {
56 Error::Custom(msg.to_string())
57 }
58}
59
60type Out = form_urlencoded::Serializer<'static, String>;
61
62fn write_field<T: Serialize + ?Sized>(out: &mut Out, key: &str, value: &T) -> Result<(), Error> {
64 match value.serialize(ScalarSerializer) {
65 Ok(Some(text)) => {
66 out.append_pair(key, &text);
67 Ok(())
68 }
69 Ok(None) => Ok(()),
70 Err(Error::NotScalar) => {
71 let json = serde_json::to_string(value).map_err(ser::Error::custom)?;
72 out.append_pair(key, &json);
73 Ok(())
74 }
75 Err(e) => Err(e),
76 }
77}
78
79struct TopSerializer<'a> {
80 out: &'a mut Out,
81}
82
83macro_rules! top_level_only {
84 ($($name:ident($($arg:ty),*) -> $ret:ty;)*) => {
85 $(fn $name(self, $(_: $arg),*) -> Result<$ret, Error> {
86 Err(Error::Custom("form body must be a struct or map".into()))
87 })*
88 };
89}
90
91impl<'a> ser::Serializer for TopSerializer<'a> {
92 type Ok = ();
93 type Error = Error;
94 type SerializeSeq = Impossible<(), Error>;
95 type SerializeTuple = Impossible<(), Error>;
96 type SerializeTupleStruct = Impossible<(), Error>;
97 type SerializeTupleVariant = Impossible<(), Error>;
98 type SerializeMap = TopMap<'a>;
99 type SerializeStruct = Self;
100 type SerializeStructVariant = Impossible<(), Error>;
101
102 fn serialize_struct(self, _: &'static str, _: usize) -> Result<Self, Error> {
103 Ok(self)
104 }
105 fn serialize_map(self, _: Option<usize>) -> Result<TopMap<'a>, Error> {
106 Ok(TopMap {
107 out: self.out,
108 key: None,
109 })
110 }
111 fn serialize_unit_struct(self, _: &'static str) -> Result<(), Error> {
112 Ok(())
113 }
114 fn serialize_unit(self) -> Result<(), Error> {
115 Ok(())
116 }
117 fn serialize_newtype_struct<T: Serialize + ?Sized>(
118 self,
119 _: &'static str,
120 value: &T,
121 ) -> Result<(), Error> {
122 value.serialize(self)
123 }
124
125 top_level_only! {
126 serialize_bool(bool) -> ();
127 serialize_i8(i8) -> ();
128 serialize_i16(i16) -> ();
129 serialize_i32(i32) -> ();
130 serialize_i64(i64) -> ();
131 serialize_u8(u8) -> ();
132 serialize_u16(u16) -> ();
133 serialize_u32(u32) -> ();
134 serialize_u64(u64) -> ();
135 serialize_f32(f32) -> ();
136 serialize_f64(f64) -> ();
137 serialize_char(char) -> ();
138 serialize_str(&str) -> ();
139 serialize_bytes(&[u8]) -> ();
140 serialize_none() -> ();
141 serialize_unit_variant(&'static str, u32, &'static str) -> ();
142 serialize_seq(Option<usize>) -> Self::SerializeSeq;
143 serialize_tuple(usize) -> Self::SerializeTuple;
144 serialize_tuple_struct(&'static str, usize) -> Self::SerializeTupleStruct;
145 serialize_tuple_variant(&'static str, u32, &'static str, usize) -> Self::SerializeTupleVariant;
146 serialize_struct_variant(&'static str, u32, &'static str, usize) -> Self::SerializeStructVariant;
147 }
148 fn serialize_some<T: Serialize + ?Sized>(self, _: &T) -> Result<(), Error> {
149 Err(Error::Custom("form body must be a struct or map".into()))
150 }
151 fn serialize_newtype_variant<T: Serialize + ?Sized>(
152 self,
153 _: &'static str,
154 _: u32,
155 _: &'static str,
156 _: &T,
157 ) -> Result<(), Error> {
158 Err(Error::Custom("form body must be a struct or map".into()))
159 }
160}
161
162impl ser::SerializeStruct for TopSerializer<'_> {
163 type Ok = ();
164 type Error = Error;
165 fn serialize_field<T: Serialize + ?Sized>(
166 &mut self,
167 key: &'static str,
168 value: &T,
169 ) -> Result<(), Error> {
170 write_field(self.out, key, value)
171 }
172 fn end(self) -> Result<(), Error> {
173 Ok(())
174 }
175}
176
177struct TopMap<'a> {
178 out: &'a mut Out,
179 key: Option<String>,
180}
181
182impl ser::SerializeMap for TopMap<'_> {
183 type Ok = ();
184 type Error = Error;
185 fn serialize_key<T: Serialize + ?Sized>(&mut self, key: &T) -> Result<(), Error> {
186 match key.serialize(ScalarSerializer)? {
187 Some(k) => {
188 self.key = Some(k);
189 Ok(())
190 }
191 None => Err(Error::Custom("map key must not be null".into())),
192 }
193 }
194 fn serialize_value<T: Serialize + ?Sized>(&mut self, value: &T) -> Result<(), Error> {
195 let key = self
196 .key
197 .take()
198 .ok_or_else(|| Error::Custom("map value without key".into()))?;
199 write_field(self.out, &key, value)
200 }
201 fn end(self) -> Result<(), Error> {
202 Ok(())
203 }
204}
205
206struct ScalarSerializer;
208
209macro_rules! scalar_display {
210 ($($name:ident($ty:ty);)*) => {
211 $(fn $name(self, v: $ty) -> Result<Option<String>, Error> {
212 Ok(Some(v.to_string()))
213 })*
214 };
215}
216
217impl ser::Serializer for ScalarSerializer {
218 type Ok = Option<String>;
219 type Error = Error;
220 type SerializeSeq = JoinSeq;
221 type SerializeTuple = Impossible<Option<String>, Error>;
222 type SerializeTupleStruct = Impossible<Option<String>, Error>;
223 type SerializeTupleVariant = Impossible<Option<String>, Error>;
224 type SerializeMap = Impossible<Option<String>, Error>;
225 type SerializeStruct = Impossible<Option<String>, Error>;
226 type SerializeStructVariant = Impossible<Option<String>, Error>;
227
228 scalar_display! {
229 serialize_bool(bool);
230 serialize_i8(i8);
231 serialize_i16(i16);
232 serialize_i32(i32);
233 serialize_i64(i64);
234 serialize_u8(u8);
235 serialize_u16(u16);
236 serialize_u32(u32);
237 serialize_u64(u64);
238 serialize_f32(f32);
239 serialize_f64(f64);
240 serialize_char(char);
241 }
242 fn serialize_str(self, v: &str) -> Result<Option<String>, Error> {
243 Ok(Some(v.to_owned()))
244 }
245 fn serialize_bytes(self, _: &[u8]) -> Result<Option<String>, Error> {
246 Err(Error::NotScalar)
247 }
248 fn serialize_none(self) -> Result<Option<String>, Error> {
249 Ok(None)
250 }
251 fn serialize_some<T: Serialize + ?Sized>(self, value: &T) -> Result<Option<String>, Error> {
252 value.serialize(self)
253 }
254 fn serialize_unit(self) -> Result<Option<String>, Error> {
255 Ok(None)
256 }
257 fn serialize_unit_struct(self, _: &'static str) -> Result<Option<String>, Error> {
258 Ok(None)
259 }
260 fn serialize_unit_variant(
261 self,
262 _: &'static str,
263 _: u32,
264 variant: &'static str,
265 ) -> Result<Option<String>, Error> {
266 Ok(Some(variant.to_owned()))
267 }
268 fn serialize_newtype_struct<T: Serialize + ?Sized>(
269 self,
270 _: &'static str,
271 value: &T,
272 ) -> Result<Option<String>, Error> {
273 value.serialize(self)
274 }
275 fn serialize_newtype_variant<T: Serialize + ?Sized>(
276 self,
277 _: &'static str,
278 _: u32,
279 _: &'static str,
280 _: &T,
281 ) -> Result<Option<String>, Error> {
282 Err(Error::NotScalar)
283 }
284 fn serialize_seq(self, _: Option<usize>) -> Result<JoinSeq, Error> {
285 Ok(JoinSeq {
286 joined: String::new(),
287 first: true,
288 })
289 }
290 fn serialize_tuple(self, _: usize) -> Result<Self::SerializeTuple, Error> {
291 Err(Error::NotScalar)
292 }
293 fn serialize_tuple_struct(
294 self,
295 _: &'static str,
296 _: usize,
297 ) -> Result<Self::SerializeTupleStruct, Error> {
298 Err(Error::NotScalar)
299 }
300 fn serialize_tuple_variant(
301 self,
302 _: &'static str,
303 _: u32,
304 _: &'static str,
305 _: usize,
306 ) -> Result<Self::SerializeTupleVariant, Error> {
307 Err(Error::NotScalar)
308 }
309 fn serialize_map(self, _: Option<usize>) -> Result<Self::SerializeMap, Error> {
310 Err(Error::NotScalar)
311 }
312 fn serialize_struct(self, _: &'static str, _: usize) -> Result<Self::SerializeStruct, Error> {
313 Err(Error::NotScalar)
314 }
315 fn serialize_struct_variant(
316 self,
317 _: &'static str,
318 _: u32,
319 _: &'static str,
320 _: usize,
321 ) -> Result<Self::SerializeStructVariant, Error> {
322 Err(Error::NotScalar)
323 }
324}
325
326struct JoinSeq {
328 joined: String,
329 first: bool,
330}
331
332impl ser::SerializeSeq for JoinSeq {
333 type Ok = Option<String>;
334 type Error = Error;
335 fn serialize_element<T: Serialize + ?Sized>(&mut self, value: &T) -> Result<(), Error> {
336 let text = value.serialize(ScalarSerializer)?.ok_or(Error::NotScalar)?;
338 if !self.first {
339 self.joined.push(',');
340 }
341 self.first = false;
342 self.joined.push_str(&text);
343 Ok(())
344 }
345 fn end(self) -> Result<Option<String>, Error> {
346 Ok(Some(self.joined))
347 }
348}
349
350#[cfg(test)]
351mod tests {
352 use super::*;
353 use serde::Serialize;
354 use serde_json::json;
355 use std::collections::BTreeMap;
356
357 #[derive(Serialize)]
358 struct Req {
359 channel: String,
360 limit: Option<i64>,
361 inclusive: Option<bool>,
362 ratio: f64,
363 users: Vec<String>,
364 blocks: Vec<serde_json::Value>,
365 skipped: Option<String>,
366 #[serde(serialize_with = "as_json")]
367 ids: Vec<String>,
368 letter: char,
369 kind: Kind,
370 unit: (),
371 wrapped: Wrapped,
372 }
373
374 #[derive(Serialize)]
375 #[serde(rename_all = "snake_case")]
376 enum Kind {
377 PublicChannel,
378 }
379
380 #[derive(Serialize)]
381 struct Wrapped(u8);
382
383 fn sample() -> Req {
384 Req {
385 channel: "C1 #x&y".into(),
386 limit: Some(200),
387 inclusive: Some(true),
388 ratio: 1.5,
389 users: vec!["U1".into(), "U2".into()],
390 blocks: vec![json!({"type": "divider"})],
391 skipped: None,
392 ids: vec!["A".into(), "B".into()],
393 letter: 'z',
394 kind: Kind::PublicChannel,
395 unit: (),
396 wrapped: Wrapped(7),
397 }
398 }
399
400 fn decode(body: &str) -> Vec<(String, String)> {
401 form_urlencoded::parse(body.as_bytes())
402 .into_owned()
403 .collect()
404 }
405
406 #[test]
407 fn struct_fields_follow_slack_conventions() {
408 let pairs = decode(&to_form(&sample()).unwrap());
409 assert_eq!(
410 pairs,
411 vec![
412 ("channel".into(), "C1 #x&y".into()),
413 ("limit".into(), "200".into()),
414 ("inclusive".into(), "true".into()),
415 ("ratio".into(), "1.5".into()),
416 ("users".into(), "U1,U2".into()),
417 ("blocks".into(), r#"[{"type":"divider"}]"#.into()),
418 ("ids".into(), r#"["A","B"]"#.into()),
419 ("letter".into(), "z".into()),
420 ("kind".into(), "public_channel".into()),
421 ("wrapped".into(), "7".into()),
422 ]
423 );
424 }
425
426 #[test]
427 fn integer_widths_are_written_as_numbers() {
428 #[derive(Serialize)]
429 struct Ints {
430 a: i8,
431 b: i16,
432 c: i32,
433 d: u16,
434 e: u32,
435 f: u64,
436 g: f32,
437 }
438 let body = to_form(&Ints {
439 a: -1,
440 b: 2,
441 c: 3,
442 d: 4,
443 e: 5,
444 f: 6,
445 g: 0.5,
446 })
447 .unwrap();
448 assert_eq!(body, "a=-1&b=2&c=3&d=4&e=5&f=6&g=0.5");
449 }
450
451 #[test]
452 fn map_and_value_bodies() {
453 let mut map = BTreeMap::new();
454 map.insert("channel", json!("C1"));
455 map.insert("nested", json!({"a": 1}));
456 map.insert("null", serde_json::Value::Null);
457 map.insert("list", json!(["x", 1, true]));
458 map.insert("mixed", json!(["x", null]));
459 assert_eq!(
460 decode(&to_form(&map).unwrap()),
461 vec![
462 ("channel".into(), "C1".into()),
463 ("list".into(), "x,1,true".into()),
464 ("mixed".into(), r#"["x",null]"#.into()),
465 ("nested".into(), r#"{"a":1}"#.into()),
466 ]
467 );
468 assert_eq!(to_form(&json!({"a": "b"})).unwrap(), "a=b");
469 }
470
471 #[test]
472 fn non_scalar_shapes_fall_back_to_json() {
473 #[derive(Serialize)]
474 enum Shape {
475 New(u8),
476 Tuple(u8, u8),
477 Struct { x: u8 },
478 }
479 #[derive(Serialize)]
480 struct TupleStruct(u8, u8);
481 #[derive(Serialize)]
482 struct Inner {
483 x: u8,
484 }
485 #[derive(Serialize)]
486 struct Req<'a> {
487 new: Shape,
488 tuple_variant: Shape,
489 struct_variant: Shape,
490 tuple: (u8, u8),
491 tuple_struct: TupleStruct,
492 inner: Inner,
493 #[serde(with = "serde_bytes_like")]
494 bytes: &'a [u8],
495 }
496 mod serde_bytes_like {
497 pub fn serialize<S: serde::Serializer>(v: &&[u8], s: S) -> Result<S::Ok, S::Error> {
498 s.serialize_bytes(v)
499 }
500 }
501 let body = to_form(&Req {
502 new: Shape::New(1),
503 tuple_variant: Shape::Tuple(1, 2),
504 struct_variant: Shape::Struct { x: 3 },
505 tuple: (4, 5),
506 tuple_struct: TupleStruct(6, 7),
507 inner: Inner { x: 8 },
508 bytes: b"hi",
509 })
510 .unwrap();
511 assert_eq!(
512 decode(&body),
513 vec![
514 ("new".into(), r#"{"New":1}"#.into()),
515 ("tuple_variant".into(), r#"{"Tuple":[1,2]}"#.into()),
516 ("struct_variant".into(), r#"{"Struct":{"x":3}}"#.into()),
517 ("tuple".into(), "[4,5]".into()),
518 ("tuple_struct".into(), "[6,7]".into()),
519 ("inner".into(), r#"{"x":8}"#.into()),
520 ("bytes".into(), "[104,105]".into()),
521 ]
522 );
523 }
524
525 #[test]
526 fn unit_struct_fields_are_skipped() {
527 #[derive(Serialize)]
528 struct Marker;
529 #[derive(Serialize)]
530 struct Req {
531 a: Marker,
532 b: u8,
533 }
534 assert_eq!(to_form(&Req { a: Marker, b: 1 }).unwrap(), "b=1");
535 }
536
537 #[test]
538 fn unit_and_newtype_top_levels() {
539 #[derive(Serialize)]
540 struct Empty;
541 #[derive(Serialize)]
542 struct Newtype(BTreeMap<&'static str, &'static str>);
543 assert_eq!(to_form(&Empty).unwrap(), "");
544 assert_eq!(to_form(&()).unwrap(), "");
545 assert_eq!(
546 to_form(&Newtype(BTreeMap::from([("a", "b")]))).unwrap(),
547 "a=b"
548 );
549 }
550
551 #[test]
552 fn scalar_top_levels_are_rejected() {
553 #[derive(Serialize)]
554 enum E {
555 Unit,
556 New(u8),
557 Tuple(u8),
558 Struct { x: u8 },
559 }
560 #[derive(Serialize)]
561 struct TupleStruct(u8, u8);
562 let rejected: Vec<Result<String, Error>> = vec![
563 to_form(&true),
564 to_form(&1i8),
565 to_form(&1i16),
566 to_form(&1i32),
567 to_form(&1i64),
568 to_form(&1u8),
569 to_form(&1u16),
570 to_form(&1u32),
571 to_form(&1u64),
572 to_form(&1f32),
573 to_form(&1f64),
574 to_form(&'c'),
575 to_form("s"),
576 to_form(&Some(1)),
577 to_form(&E::Unit),
578 to_form(&E::New(1)),
579 to_form(&E::Struct { x: 1 }),
580 to_form(&vec![1]),
581 to_form(&(1, 2)),
582 to_form(&TupleStruct(1, 2)),
583 to_form(&E::Tuple(1)),
584 to_form(&Option::<u8>::None),
585 ];
586 for r in rejected {
587 let err = r.unwrap_err();
588 assert_eq!(err.to_string(), "form body must be a struct or map");
589 }
590 assert!(to_form(serde_bytes_ref(b"x")).is_err());
591 }
592
593 struct BytesRef<'a>(&'a [u8]);
594 impl Serialize for BytesRef<'_> {
595 fn serialize<S: ser::Serializer>(&self, s: S) -> Result<S::Ok, S::Error> {
596 s.serialize_bytes(self.0)
597 }
598 }
599 fn serde_bytes_ref(b: &[u8]) -> &BytesRef<'_> {
600 Box::leak(Box::new(BytesRef(b)))
601 }
602
603 #[test]
604 fn map_key_errors() {
605 let mut null_key = BTreeMap::new();
606 null_key.insert(Option::<&str>::None, 1);
607 assert_eq!(
608 to_form(&null_key).unwrap_err().to_string(),
609 "map key must not be null"
610 );
611
612 let mut struct_key = BTreeMap::new();
613 struct_key.insert(vec![("a", 1)], 1);
614 assert_eq!(
616 to_form(&struct_key).unwrap_err().to_string(),
617 "value is not a scalar"
618 );
619 }
620
621 #[test]
622 fn value_without_key_is_an_error() {
623 use ser::SerializeMap;
624 let mut out = form_urlencoded::Serializer::new(String::new());
625 let mut map = TopMap {
626 out: &mut out,
627 key: None,
628 };
629 assert_eq!(
630 map.serialize_value(&1).unwrap_err().to_string(),
631 "map value without key"
632 );
633 }
634
635 #[test]
636 fn custom_errors_propagate() {
637 struct Fails;
638 impl Serialize for Fails {
639 fn serialize<S: ser::Serializer>(&self, _: S) -> Result<S::Ok, S::Error> {
640 Err(ser::Error::custom("boom"))
641 }
642 }
643 #[derive(Serialize)]
644 struct Req {
645 f: Fails,
646 }
647 assert_eq!(to_form(&Req { f: Fails }).unwrap_err().to_string(), "boom");
648
649 #[derive(Serialize)]
651 struct Bad {
652 m: BTreeMap<Vec<u8>, u8>,
653 }
654 let err = to_form(&Bad {
655 m: BTreeMap::from([(vec![1], 1)]),
656 })
657 .unwrap_err();
658 assert!(matches!(err, Error::Custom(_)));
659
660 #[derive(Serialize)]
661 struct BadJson {
662 #[serde(serialize_with = "as_json")]
663 m: BTreeMap<Vec<u8>, u8>,
664 }
665 assert!(to_form(&BadJson {
666 m: BTreeMap::from([(vec![1], 1)])
667 })
668 .is_err());
669 }
670}