1use std::{borrow::Cow, fmt::Display};
73
74use itertools::Itertools;
75use percent_encoding::{AsciiSet, CONTROLS, PercentEncode};
76use serde::{
77 Serialize,
78 ser::{Impossible, SerializeMap, SerializeSeq, SerializeStruct, SerializeTuple, Serializer},
79};
80use url::Url;
81
82#[derive(Debug, Clone, Copy, PartialEq, Eq)]
84pub enum QueryStyle {
85 Form { exploded: bool },
90
91 SpaceDelimited,
93
94 PipeDelimited,
96
97 DeepObject,
99}
100
101impl Default for QueryStyle {
102 fn default() -> Self {
103 Self::Form { exploded: true }
104 }
105}
106
107pub struct QuerySerializer<'a> {
110 url: Url,
111 styles: &'a [(&'a str, QueryStyle)],
112}
113
114impl<'a> QuerySerializer<'a> {
115 pub fn new(url: Url, styles: &'a [(&'a str, QueryStyle)]) -> Self {
117 Self { url, styles }
118 }
119}
120
121impl<'a> Serializer for QuerySerializer<'a> {
122 type Ok = Url;
123 type Error = QueryParamError;
124
125 type SerializeSeq = Impossible<Self::Ok, Self::Error>;
126 type SerializeTuple = Impossible<Self::Ok, Self::Error>;
127 type SerializeTupleStruct = Impossible<Self::Ok, Self::Error>;
128 type SerializeTupleVariant = Impossible<Self::Ok, Self::Error>;
129 type SerializeMap = Impossible<Self::Ok, Self::Error>;
130 type SerializeStruct = Self;
131 type SerializeStructVariant = Impossible<Self::Ok, Self::Error>;
132
133 fn serialize_struct(
134 self,
135 _: &'static str,
136 _: usize,
137 ) -> Result<Self::SerializeStruct, Self::Error> {
138 Ok(self)
139 }
140
141 fn serialize_bool(self, _: bool) -> Result<Self::Ok, Self::Error> {
142 Err(QueryParamError::ExpectedStruct)
143 }
144
145 fn serialize_i8(self, _: i8) -> Result<Self::Ok, Self::Error> {
146 Err(QueryParamError::ExpectedStruct)
147 }
148
149 fn serialize_i16(self, _: i16) -> Result<Self::Ok, Self::Error> {
150 Err(QueryParamError::ExpectedStruct)
151 }
152
153 fn serialize_i32(self, _: i32) -> Result<Self::Ok, Self::Error> {
154 Err(QueryParamError::ExpectedStruct)
155 }
156
157 fn serialize_i64(self, _: i64) -> Result<Self::Ok, Self::Error> {
158 Err(QueryParamError::ExpectedStruct)
159 }
160
161 fn serialize_u8(self, _: u8) -> Result<Self::Ok, Self::Error> {
162 Err(QueryParamError::ExpectedStruct)
163 }
164
165 fn serialize_u16(self, _: u16) -> Result<Self::Ok, Self::Error> {
166 Err(QueryParamError::ExpectedStruct)
167 }
168
169 fn serialize_u32(self, _: u32) -> Result<Self::Ok, Self::Error> {
170 Err(QueryParamError::ExpectedStruct)
171 }
172
173 fn serialize_u64(self, _: u64) -> Result<Self::Ok, Self::Error> {
174 Err(QueryParamError::ExpectedStruct)
175 }
176
177 fn serialize_f32(self, _: f32) -> Result<Self::Ok, Self::Error> {
178 Err(QueryParamError::ExpectedStruct)
179 }
180
181 fn serialize_f64(self, _: f64) -> Result<Self::Ok, Self::Error> {
182 Err(QueryParamError::ExpectedStruct)
183 }
184
185 fn serialize_char(self, _: char) -> Result<Self::Ok, Self::Error> {
186 Err(QueryParamError::ExpectedStruct)
187 }
188
189 fn serialize_str(self, _: &str) -> Result<Self::Ok, Self::Error> {
190 Err(QueryParamError::ExpectedStruct)
191 }
192
193 fn serialize_bytes(self, _: &[u8]) -> Result<Self::Ok, Self::Error> {
194 Err(QueryParamError::ExpectedStruct)
195 }
196
197 fn serialize_none(self) -> Result<Self::Ok, Self::Error> {
198 Err(QueryParamError::ExpectedStruct)
199 }
200
201 fn serialize_some<T: ?Sized + Serialize>(self, _: &T) -> Result<Self::Ok, Self::Error> {
202 Err(QueryParamError::ExpectedStruct)
203 }
204
205 fn serialize_unit(self) -> Result<Self::Ok, Self::Error> {
206 Err(QueryParamError::ExpectedStruct)
207 }
208
209 fn serialize_unit_struct(self, _: &'static str) -> Result<Self::Ok, Self::Error> {
210 Err(QueryParamError::ExpectedStruct)
211 }
212
213 fn serialize_unit_variant(
214 self,
215 _: &'static str,
216 _: u32,
217 _: &'static str,
218 ) -> Result<Self::Ok, Self::Error> {
219 Err(QueryParamError::ExpectedStruct)
220 }
221
222 fn serialize_newtype_struct<T: ?Sized + Serialize>(
223 self,
224 _: &'static str,
225 _: &T,
226 ) -> Result<Self::Ok, Self::Error> {
227 Err(QueryParamError::ExpectedStruct)
228 }
229
230 fn serialize_newtype_variant<T: ?Sized + Serialize>(
231 self,
232 _: &'static str,
233 _: u32,
234 _: &'static str,
235 _: &T,
236 ) -> Result<Self::Ok, Self::Error> {
237 Err(QueryParamError::ExpectedStruct)
238 }
239
240 fn serialize_seq(self, _: Option<usize>) -> Result<Self::SerializeSeq, Self::Error> {
241 Err(QueryParamError::ExpectedStruct)
242 }
243
244 fn serialize_tuple(self, _: usize) -> Result<Self::SerializeTuple, Self::Error> {
245 Err(QueryParamError::ExpectedStruct)
246 }
247
248 fn serialize_tuple_struct(
249 self,
250 _: &'static str,
251 _: usize,
252 ) -> Result<Self::SerializeTupleStruct, Self::Error> {
253 Err(QueryParamError::ExpectedStruct)
254 }
255
256 fn serialize_tuple_variant(
257 self,
258 _: &'static str,
259 _: u32,
260 _: &'static str,
261 _: usize,
262 ) -> Result<Self::SerializeTupleVariant, Self::Error> {
263 Err(QueryParamError::ExpectedStruct)
264 }
265
266 fn serialize_map(self, _: Option<usize>) -> Result<Self::SerializeMap, Self::Error> {
267 Err(QueryParamError::ExpectedStruct)
268 }
269
270 fn serialize_struct_variant(
271 self,
272 _: &'static str,
273 _: u32,
274 _: &'static str,
275 _: usize,
276 ) -> Result<Self::SerializeStructVariant, Self::Error> {
277 Err(QueryParamError::ExpectedStruct)
278 }
279}
280
281impl SerializeStruct for QuerySerializer<'_> {
282 type Ok = Url;
283 type Error = QueryParamError;
284
285 fn serialize_field<T: ?Sized + Serialize>(
286 &mut self,
287 key: &'static str,
288 value: &T,
289 ) -> Result<(), Self::Error> {
290 let style = self
291 .styles
292 .iter()
293 .find(|&&(name, _)| name == key)
294 .map(|&(_, style)| style)
295 .unwrap_or_default();
296 let mut path = KeyPath::new(key);
297 let mut serializer = QueryParamSerializer::new(
298 &mut self.url,
299 &mut path,
300 ParamSerializerState::for_style(style),
301 );
302 value.serialize(&mut serializer)?;
303 serializer.flush();
304 Ok(())
305 }
306
307 fn end(self) -> Result<Self::Ok, Self::Error> {
308 Ok(self.url)
309 }
310}
311
312#[derive(Debug)]
313enum ParamSerializerState {
314 Delimited(&'static str, Vec<String>),
316 ExplodedForm,
318 NonExplodedForm(Vec<String>),
320 DeepObject,
322}
323
324impl ParamSerializerState {
325 fn for_style(style: QueryStyle) -> Self {
327 match style {
328 QueryStyle::DeepObject => Self::DeepObject,
329 QueryStyle::Form { exploded: true } => Self::ExplodedForm,
330 QueryStyle::Form { exploded: false } => Self::NonExplodedForm(vec![]),
331 QueryStyle::PipeDelimited => Self::Delimited("|", vec![]),
332 QueryStyle::SpaceDelimited => Self::Delimited(" ", vec![]),
333 }
334 }
335}
336
337#[derive(Clone, Debug)]
338struct KeyPath<'a>(Cow<'a, str>, Vec<Cow<'a, str>>);
339
340impl<'a> KeyPath<'a> {
341 fn new(head: impl Into<Cow<'a, str>>) -> Self {
342 Self(head.into(), vec![])
343 }
344
345 fn len(&self) -> usize {
346 self.1.len() + 1
347 }
348
349 fn push(&mut self, segment: impl Into<Cow<'a, str>>) {
350 self.1.push(segment.into());
351 }
352
353 fn pop(&mut self) -> Cow<'_, str> {
354 self.1.pop().unwrap_or_else(|| Cow::Borrowed(&self.0))
355 }
356
357 fn first(&self) -> &str {
358 &self.0
359 }
360
361 fn last(&self) -> &str {
362 self.1.last().unwrap_or(&self.0)
363 }
364
365 fn split_first(&self) -> (&str, &[Cow<'a, str>]) {
366 (&self.0, &self.1)
367 }
368}
369
370const COMPONENT: &AsciiSet = &CONTROLS
381 .add(b' ')
382 .add(b'"')
383 .add(b'#')
384 .add(b'<')
385 .add(b'>')
386 .add(b'?')
387 .add(b'`')
388 .add(b'^')
389 .add(b'{')
390 .add(b'}')
391 .add(b'/')
392 .add(b':')
393 .add(b';')
394 .add(b'=')
395 .add(b'@')
396 .add(b'[')
397 .add(b'\\')
398 .add(b']')
399 .add(b'|')
400 .add(b'$')
401 .add(b'%')
402 .add(b'&')
403 .add(b'+')
404 .add(b',');
405
406#[derive(Clone, Debug)]
407enum EncodedOrRaw<'a> {
408 Encoded(PercentEncode<'a>),
409 Raw(&'a str),
410}
411
412impl<'a> EncodedOrRaw<'a> {
413 fn encode(input: &'a str) -> Self {
414 Self::Encoded(percent_encoding::utf8_percent_encode(input, COMPONENT))
415 }
416}
417
418impl Display for EncodedOrRaw<'_> {
419 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
420 match self {
421 Self::Encoded(s) => write!(f, "{s}"),
422 Self::Raw(s) => f.write_str(s),
423 }
424 }
425}
426
427#[derive(Debug)]
428struct PercentEncodeDelimited<'a, T>(&'a [T], EncodedOrRaw<'a>);
429
430impl<T: AsRef<str>> Display for PercentEncodeDelimited<'_, T> {
431 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
432 write!(
433 f,
434 "{}",
435 Itertools::intersperse(
438 self.0
439 .iter()
440 .map(|input| input.as_ref())
441 .map(EncodedOrRaw::encode),
442 self.1.clone()
443 )
444 .format("")
445 )
446 }
447}
448
449#[derive(Debug)]
451struct QueryParamSerializer<'a> {
452 url: &'a mut Url,
454 path: &'a mut KeyPath<'a>,
458 state: ParamSerializerState,
459}
460
461impl<'a> QueryParamSerializer<'a> {
462 fn new(url: &'a mut Url, path: &'a mut KeyPath<'a>, state: ParamSerializerState) -> Self {
464 Self { url, path, state }
465 }
466
467 fn key(&self) -> Cow<'_, str> {
469 use ParamSerializerState::*;
470 match &self.state {
471 DeepObject => {
472 match self.path.split_first() {
474 (head, []) => head.into(),
475 (head, rest) => format!("{head}[{}]", rest.iter().format("][")).into(),
476 }
477 }
478 ExplodedForm => {
479 self.path.last().into()
481 }
482 NonExplodedForm(_) | Delimited(_, _) => {
483 self.path.first().into()
485 }
486 }
487 }
488
489 fn append<'b>(&mut self, value: impl Into<Cow<'b, str>>) {
491 use ParamSerializerState::*;
492 let value = value.into();
493 match &mut self.state {
494 NonExplodedForm(buf) | Delimited(_, buf) => {
495 buf.push(value.into_owned());
496 }
497 DeepObject | ExplodedForm => {
498 let key = self.key().into_owned();
502 self.url.query_pairs_mut().append_pair(&key, &value);
503 }
504 }
505 }
506
507 fn flush(&mut self) {
512 use ParamSerializerState::*;
513 let (delimiter, buf) = match &mut self.state {
514 NonExplodedForm(buf) => (
515 EncodedOrRaw::Raw(","),
517 std::mem::take(buf),
518 ),
519 Delimited(delimiter, buf) => (
520 EncodedOrRaw::encode(delimiter),
522 std::mem::take(buf),
523 ),
524 _ => return,
525 };
526 if buf.is_empty() {
527 return;
528 }
529
530 let key = self.key();
531 let key = EncodedOrRaw::encode(&key);
532 let value = PercentEncodeDelimited(&buf, delimiter);
533
534 let new_query = match self.url.query().map(|q| q.trim_end_matches('&')) {
538 Some(query) if !query.is_empty() => format!("{query}&{key}={value}"),
539 _ => format!("{key}={value}"),
540 };
541 self.url.set_query(Some(&new_query));
542 }
543}
544
545impl<'a, 'b> Serializer for &'a mut QueryParamSerializer<'b> {
546 type Ok = ();
547 type Error = QueryParamError;
548
549 type SerializeSeq = QuerySeqSerializer<'a, 'b>;
550 type SerializeTuple = QuerySeqSerializer<'a, 'b>;
551 type SerializeTupleStruct = Impossible<Self::Ok, Self::Error>;
552 type SerializeTupleVariant = Impossible<Self::Ok, Self::Error>;
553 type SerializeMap = QueryStructSerializer<'a, 'b>;
554 type SerializeStruct = QueryStructSerializer<'a, 'b>;
555 type SerializeStructVariant = Impossible<Self::Ok, Self::Error>;
556
557 fn serialize_bool(self, v: bool) -> Result<Self::Ok, Self::Error> {
558 self.append(if v { "true" } else { "false" });
559 Ok(())
560 }
561
562 fn serialize_i8(self, v: i8) -> Result<Self::Ok, Self::Error> {
563 self.append(v.to_string());
564 Ok(())
565 }
566
567 fn serialize_i16(self, v: i16) -> Result<Self::Ok, Self::Error> {
568 self.append(v.to_string());
569 Ok(())
570 }
571
572 fn serialize_i32(self, v: i32) -> Result<Self::Ok, Self::Error> {
573 self.append(v.to_string());
574 Ok(())
575 }
576
577 fn serialize_i64(self, v: i64) -> Result<Self::Ok, Self::Error> {
578 self.append(v.to_string());
579 Ok(())
580 }
581
582 fn serialize_u8(self, v: u8) -> Result<Self::Ok, Self::Error> {
583 self.append(v.to_string());
584 Ok(())
585 }
586
587 fn serialize_u16(self, v: u16) -> Result<Self::Ok, Self::Error> {
588 self.append(v.to_string());
589 Ok(())
590 }
591
592 fn serialize_u32(self, v: u32) -> Result<Self::Ok, Self::Error> {
593 self.append(v.to_string());
594 Ok(())
595 }
596
597 fn serialize_u64(self, v: u64) -> Result<Self::Ok, Self::Error> {
598 self.append(v.to_string());
599 Ok(())
600 }
601
602 fn serialize_f32(self, v: f32) -> Result<Self::Ok, Self::Error> {
603 self.append(v.to_string());
604 Ok(())
605 }
606
607 fn serialize_f64(self, v: f64) -> Result<Self::Ok, Self::Error> {
608 self.append(v.to_string());
609 Ok(())
610 }
611
612 fn serialize_char(self, v: char) -> Result<Self::Ok, Self::Error> {
613 self.append(v.to_string());
614 Ok(())
615 }
616
617 fn serialize_str(self, v: &str) -> Result<Self::Ok, Self::Error> {
618 self.append(v);
619 Ok(())
620 }
621
622 fn serialize_bytes(self, _: &[u8]) -> Result<Self::Ok, Self::Error> {
623 Err(UnsupportedTypeError::Bytes)?
624 }
625
626 fn serialize_none(self) -> Result<Self::Ok, Self::Error> {
627 Ok(())
629 }
630
631 fn serialize_some<T: ?Sized + Serialize>(self, value: &T) -> Result<Self::Ok, Self::Error> {
632 value.serialize(self)
633 }
634
635 fn serialize_unit(self) -> Result<Self::Ok, Self::Error> {
636 Err(UnsupportedTypeError::Unit)?
637 }
638
639 fn serialize_unit_struct(self, name: &'static str) -> Result<Self::Ok, Self::Error> {
640 Err(UnsupportedTypeError::UnitStruct(name))?
641 }
642
643 fn serialize_unit_variant(
644 self,
645 _name: &'static str,
646 _index: u32,
647 variant: &'static str,
648 ) -> Result<Self::Ok, Self::Error> {
649 self.append(variant);
650 Ok(())
651 }
652
653 fn serialize_newtype_struct<T: ?Sized + Serialize>(
654 self,
655 _name: &'static str,
656 value: &T,
657 ) -> Result<Self::Ok, Self::Error> {
658 value.serialize(self)
659 }
660
661 fn serialize_newtype_variant<T: ?Sized + Serialize>(
662 self,
663 name: &'static str,
664 _index: u32,
665 variant: &'static str,
666 _value: &T,
667 ) -> Result<Self::Ok, Self::Error> {
668 Err(UnsupportedTypeError::NewtypeVariant(name, variant))?
669 }
670
671 fn serialize_seq(self, _len: Option<usize>) -> Result<Self::SerializeSeq, Self::Error> {
672 Ok(QuerySeqSerializer {
673 serializer: self,
674 index: 0,
675 })
676 }
677
678 fn serialize_tuple(self, _len: usize) -> Result<Self::SerializeTuple, Self::Error> {
679 Ok(QuerySeqSerializer {
680 serializer: self,
681 index: 0,
682 })
683 }
684
685 fn serialize_tuple_struct(
686 self,
687 name: &'static str,
688 _len: usize,
689 ) -> Result<Self::SerializeTupleStruct, Self::Error> {
690 Err(UnsupportedTypeError::TupleStruct(name))?
691 }
692
693 fn serialize_tuple_variant(
694 self,
695 name: &'static str,
696 _index: u32,
697 variant: &'static str,
698 _len: usize,
699 ) -> Result<Self::SerializeTupleVariant, Self::Error> {
700 Err(UnsupportedTypeError::TupleVariant(name, variant))?
701 }
702
703 fn serialize_map(self, _len: Option<usize>) -> Result<Self::SerializeMap, Self::Error> {
704 Ok(QueryStructSerializer { serializer: self })
705 }
706
707 fn serialize_struct(
708 self,
709 _name: &'static str,
710 _len: usize,
711 ) -> Result<Self::SerializeStruct, Self::Error> {
712 Ok(QueryStructSerializer { serializer: self })
713 }
714
715 fn serialize_struct_variant(
716 self,
717 name: &'static str,
718 _index: u32,
719 variant: &'static str,
720 _len: usize,
721 ) -> Result<Self::SerializeStructVariant, Self::Error> {
722 Err(UnsupportedTypeError::StructVariant(name, variant))?
723 }
724}
725
726pub struct QuerySeqSerializer<'a, 'b> {
728 serializer: &'a mut QueryParamSerializer<'b>,
729 index: usize,
730}
731
732impl<'a, 'b> SerializeSeq for QuerySeqSerializer<'a, 'b> {
733 type Ok = ();
734 type Error = QueryParamError;
735
736 fn serialize_element<T: ?Sized + Serialize>(&mut self, value: &T) -> Result<(), Self::Error> {
737 use ParamSerializerState::*;
738 match &mut self.serializer.state {
739 DeepObject if self.serializer.path.len() == 1 => {
740 return Err(QueryParamError::UnspecifiedStyleExploded);
743 }
744 DeepObject => {
745 self.serializer.path.push(self.index.to_string());
747 value.serialize(&mut *self.serializer)?;
748 self.serializer.path.pop();
749 }
750 _ => value.serialize(&mut *self.serializer)?,
751 }
752 self.index += 1;
753 Ok(())
754 }
755
756 fn end(self) -> Result<Self::Ok, Self::Error> {
757 self.serializer.flush();
758 Ok(())
759 }
760}
761
762impl<'a, 'b> SerializeTuple for QuerySeqSerializer<'a, 'b> {
763 type Ok = ();
764 type Error = QueryParamError;
765
766 fn serialize_element<T: ?Sized + Serialize>(&mut self, value: &T) -> Result<(), Self::Error> {
767 SerializeSeq::serialize_element(self, value)
768 }
769
770 fn end(self) -> Result<Self::Ok, Self::Error> {
771 SerializeSeq::end(self)
772 }
773}
774
775pub struct QueryStructSerializer<'a, 'b> {
777 serializer: &'a mut QueryParamSerializer<'b>,
778}
779
780impl<'a, 'b> SerializeStruct for QueryStructSerializer<'a, 'b> {
781 type Ok = ();
782 type Error = QueryParamError;
783
784 fn serialize_field<T: ?Sized + Serialize>(
785 &mut self,
786 key: &'static str,
787 value: &T,
788 ) -> Result<(), Self::Error> {
789 use ParamSerializerState::*;
790 if let NonExplodedForm(buf) | Delimited(_, buf) = &mut self.serializer.state {
791 buf.push(key.to_owned());
794 };
795
796 self.serializer.path.push(key);
797 value.serialize(&mut *self.serializer)?;
798 self.serializer.path.pop();
799 Ok(())
800 }
801
802 fn end(self) -> Result<Self::Ok, Self::Error> {
803 self.serializer.flush();
804 Ok(())
805 }
806}
807
808impl<'a, 'b> SerializeMap for QueryStructSerializer<'a, 'b> {
809 type Ok = ();
810 type Error = QueryParamError;
811
812 fn serialize_key<T: ?Sized + Serialize>(&mut self, key: &T) -> Result<(), Self::Error> {
813 self.serializer.path.push(key.serialize(KeyExtractor)?);
814 Ok(())
815 }
816
817 fn serialize_value<T: ?Sized + Serialize>(&mut self, value: &T) -> Result<(), Self::Error> {
818 use ParamSerializerState::*;
819 if let NonExplodedForm(buf) | Delimited(_, buf) = &mut self.serializer.state {
820 buf.push(self.serializer.path.last().to_owned());
823 };
824
825 value.serialize(&mut *self.serializer)?;
826 self.serializer.path.pop();
827 Ok(())
828 }
829
830 fn end(self) -> Result<Self::Ok, Self::Error> {
831 self.serializer.flush();
832 Ok(())
833 }
834}
835
836struct KeyExtractor;
838
839impl Serializer for KeyExtractor {
840 type Ok = String;
841 type Error = QueryParamError;
842
843 type SerializeSeq = Impossible<Self::Ok, Self::Error>;
844 type SerializeTuple = Impossible<Self::Ok, Self::Error>;
845 type SerializeTupleStruct = Impossible<Self::Ok, Self::Error>;
846 type SerializeTupleVariant = Impossible<Self::Ok, Self::Error>;
847 type SerializeMap = Impossible<Self::Ok, Self::Error>;
848 type SerializeStruct = Impossible<Self::Ok, Self::Error>;
849 type SerializeStructVariant = Impossible<Self::Ok, Self::Error>;
850
851 fn serialize_str(self, v: &str) -> Result<Self::Ok, Self::Error> {
852 Ok(v.to_owned())
853 }
854
855 fn serialize_bool(self, _: bool) -> Result<Self::Ok, Self::Error> {
856 Err(QueryParamError::ExpectedStringKey)
857 }
858
859 fn serialize_i8(self, _: i8) -> Result<Self::Ok, Self::Error> {
860 Err(QueryParamError::ExpectedStringKey)
861 }
862
863 fn serialize_i16(self, _: i16) -> Result<Self::Ok, Self::Error> {
864 Err(QueryParamError::ExpectedStringKey)
865 }
866
867 fn serialize_i32(self, _: i32) -> Result<Self::Ok, Self::Error> {
868 Err(QueryParamError::ExpectedStringKey)
869 }
870
871 fn serialize_i64(self, _: i64) -> Result<Self::Ok, Self::Error> {
872 Err(QueryParamError::ExpectedStringKey)
873 }
874
875 fn serialize_u8(self, _: u8) -> Result<Self::Ok, Self::Error> {
876 Err(QueryParamError::ExpectedStringKey)
877 }
878
879 fn serialize_u16(self, _: u16) -> Result<Self::Ok, Self::Error> {
880 Err(QueryParamError::ExpectedStringKey)
881 }
882
883 fn serialize_u32(self, _: u32) -> Result<Self::Ok, Self::Error> {
884 Err(QueryParamError::ExpectedStringKey)
885 }
886
887 fn serialize_u64(self, _: u64) -> Result<Self::Ok, Self::Error> {
888 Err(QueryParamError::ExpectedStringKey)
889 }
890
891 fn serialize_f32(self, _: f32) -> Result<Self::Ok, Self::Error> {
892 Err(QueryParamError::ExpectedStringKey)
893 }
894
895 fn serialize_f64(self, _: f64) -> Result<Self::Ok, Self::Error> {
896 Err(QueryParamError::ExpectedStringKey)
897 }
898
899 fn serialize_char(self, _: char) -> Result<Self::Ok, Self::Error> {
900 Err(QueryParamError::ExpectedStringKey)
901 }
902
903 fn serialize_bytes(self, _: &[u8]) -> Result<Self::Ok, Self::Error> {
904 Err(QueryParamError::ExpectedStringKey)
905 }
906
907 fn serialize_none(self) -> Result<Self::Ok, Self::Error> {
908 Err(QueryParamError::ExpectedStringKey)
909 }
910
911 fn serialize_some<T: ?Sized + Serialize>(self, _: &T) -> Result<Self::Ok, Self::Error> {
912 Err(QueryParamError::ExpectedStringKey)
913 }
914
915 fn serialize_unit(self) -> Result<Self::Ok, Self::Error> {
916 Err(QueryParamError::ExpectedStringKey)
917 }
918
919 fn serialize_unit_struct(self, _: &'static str) -> Result<Self::Ok, Self::Error> {
920 Err(QueryParamError::ExpectedStringKey)
921 }
922
923 fn serialize_unit_variant(
924 self,
925 _: &'static str,
926 _: u32,
927 _: &'static str,
928 ) -> Result<Self::Ok, Self::Error> {
929 Err(QueryParamError::ExpectedStringKey)
930 }
931
932 fn serialize_newtype_struct<T: ?Sized + Serialize>(
933 self,
934 _: &'static str,
935 _: &T,
936 ) -> Result<Self::Ok, Self::Error> {
937 Err(QueryParamError::ExpectedStringKey)
938 }
939
940 fn serialize_newtype_variant<T: ?Sized + Serialize>(
941 self,
942 _: &'static str,
943 _: u32,
944 _: &'static str,
945 _: &T,
946 ) -> Result<Self::Ok, Self::Error> {
947 Err(QueryParamError::ExpectedStringKey)
948 }
949
950 fn serialize_seq(self, _: Option<usize>) -> Result<Self::SerializeSeq, Self::Error> {
951 Err(QueryParamError::ExpectedStringKey)
952 }
953
954 fn serialize_tuple(self, _: usize) -> Result<Self::SerializeTuple, Self::Error> {
955 Err(QueryParamError::ExpectedStringKey)
956 }
957
958 fn serialize_tuple_struct(
959 self,
960 _: &'static str,
961 _: usize,
962 ) -> Result<Self::SerializeTupleStruct, Self::Error> {
963 Err(QueryParamError::ExpectedStringKey)
964 }
965
966 fn serialize_tuple_variant(
967 self,
968 _: &'static str,
969 _: u32,
970 _: &'static str,
971 _: usize,
972 ) -> Result<Self::SerializeTupleVariant, Self::Error> {
973 Err(QueryParamError::ExpectedStringKey)
974 }
975
976 fn serialize_map(self, _: Option<usize>) -> Result<Self::SerializeMap, Self::Error> {
977 Err(QueryParamError::ExpectedStringKey)
978 }
979
980 fn serialize_struct(
981 self,
982 _: &'static str,
983 _: usize,
984 ) -> Result<Self::SerializeStruct, Self::Error> {
985 Err(QueryParamError::ExpectedStringKey)
986 }
987
988 fn serialize_struct_variant(
989 self,
990 _: &'static str,
991 _: u32,
992 _: &'static str,
993 _: usize,
994 ) -> Result<Self::SerializeStructVariant, Self::Error> {
995 Err(QueryParamError::ExpectedStringKey)
996 }
997}
998
999#[derive(Debug, thiserror::Error)]
1001pub enum QueryParamError {
1002 #[error("can't serialize {0} as query parameter")]
1003 UnsupportedType(#[from] UnsupportedTypeError),
1004 #[error("style-exploded combination not defined by OpenAPI")]
1005 UnspecifiedStyleExploded,
1006 #[error("map keys must serialize as strings")]
1007 ExpectedStringKey,
1008 #[error("query parameters must serialize as a struct")]
1009 ExpectedStruct,
1010 #[error("{0}")]
1011 Custom(String),
1012}
1013
1014impl serde::ser::Error for QueryParamError {
1015 fn custom<T: std::fmt::Display>(err: T) -> Self {
1016 Self::Custom(err.to_string())
1017 }
1018}
1019
1020#[derive(Debug, thiserror::Error)]
1021pub enum UnsupportedTypeError {
1022 #[error("bytes")]
1023 Bytes,
1024 #[error("unit")]
1025 Unit,
1026 #[error("unit struct `{0}`")]
1027 UnitStruct(&'static str),
1028 #[error("tuple struct `{0}`")]
1029 TupleStruct(&'static str),
1030 #[error("newtype variant `{1}` of `{0}`")]
1031 NewtypeVariant(&'static str, &'static str),
1032 #[error("tuple variant `{1}` of `{0}`")]
1033 TupleVariant(&'static str, &'static str),
1034 #[error("struct variant `{1}` of `{0}`")]
1035 StructVariant(&'static str, &'static str),
1036}
1037
1038#[cfg(test)]
1039mod tests {
1040 use super::*;
1041 use serde::Serialize;
1042 use url::Url;
1043
1044 #[test]
1047 fn test_integer() {
1048 #[derive(Serialize)]
1049 struct Q {
1050 limit: i32,
1051 }
1052
1053 let url = Q { limit: 42 }
1054 .serialize(QuerySerializer::new(
1055 Url::parse("http://example.com/").unwrap(),
1056 &[],
1057 ))
1058 .unwrap();
1059 assert_eq!(url.query(), Some("limit=42"));
1060 }
1061
1062 #[test]
1063 fn test_string() {
1064 #[derive(Serialize)]
1065 struct Q {
1066 name: &'static str,
1067 }
1068
1069 let url = Q { name: "Alice" }
1070 .serialize(QuerySerializer::new(
1071 Url::parse("http://example.com/").unwrap(),
1072 &[],
1073 ))
1074 .unwrap();
1075 assert_eq!(url.query(), Some("name=Alice"));
1076 }
1077
1078 #[test]
1079 fn test_bool() {
1080 #[derive(Serialize)]
1081 struct Q {
1082 active: bool,
1083 }
1084
1085 let url = Q { active: true }
1086 .serialize(QuerySerializer::new(
1087 Url::parse("http://example.com/").unwrap(),
1088 &[],
1089 ))
1090 .unwrap();
1091 assert_eq!(url.query(), Some("active=true"));
1092 }
1093
1094 #[test]
1095 fn test_option_some() {
1096 #[derive(Serialize)]
1097 struct Q {
1098 limit: Option<i32>,
1099 }
1100
1101 let url = Q { limit: Some(42) }
1102 .serialize(QuerySerializer::new(
1103 Url::parse("http://example.com/").unwrap(),
1104 &[],
1105 ))
1106 .unwrap();
1107 assert_eq!(url.query(), Some("limit=42"));
1108 }
1109
1110 #[test]
1111 fn test_option_none() {
1112 #[derive(Serialize)]
1113 struct Q {
1114 limit: Option<i32>,
1115 }
1116
1117 let url = Q { limit: None }
1118 .serialize(QuerySerializer::new(
1119 Url::parse("http://example.com/").unwrap(),
1120 &[],
1121 ))
1122 .unwrap();
1123 assert_eq!(url.query(), None);
1124 }
1125
1126 #[test]
1127 fn test_string_with_special_chars() {
1128 #[derive(Serialize)]
1129 struct Q {
1130 name: &'static str,
1131 }
1132
1133 let url = Q {
1134 name: "John Doe & Co.",
1135 }
1136 .serialize(QuerySerializer::new(
1137 Url::parse("http://example.com/").unwrap(),
1138 &[],
1139 ))
1140 .unwrap();
1141 assert_eq!(url.query(), Some("name=John+Doe+%26+Co."));
1142 }
1143
1144 #[test]
1145 fn test_unicode_string() {
1146 #[derive(Serialize)]
1147 struct Q {
1148 name: &'static str,
1149 }
1150
1151 let url = Q { name: "日本語" }
1152 .serialize(QuerySerializer::new(
1153 Url::parse("http://example.com/").unwrap(),
1154 &[],
1155 ))
1156 .unwrap();
1157 assert_eq!(url.query(), Some("name=%E6%97%A5%E6%9C%AC%E8%AA%9E"));
1158 }
1159
1160 #[test]
1161 fn test_unit_variant_enum() {
1162 #[derive(Serialize)]
1163 #[allow(dead_code)]
1164 enum Status {
1165 Active,
1166 Inactive,
1167 }
1168
1169 #[derive(Serialize)]
1170 struct Q {
1171 status: Status,
1172 }
1173
1174 let url = Q {
1175 status: Status::Active,
1176 }
1177 .serialize(QuerySerializer::new(
1178 Url::parse("http://example.com/").unwrap(),
1179 &[],
1180 ))
1181 .unwrap();
1182 assert_eq!(url.query(), Some("status=Active"));
1183 }
1184
1185 #[test]
1188 fn test_array_form_exploded() {
1189 #[derive(Serialize)]
1190 struct Q {
1191 ids: Vec<i32>,
1192 }
1193
1194 let url = Q { ids: vec![1, 2, 3] }
1195 .serialize(QuerySerializer::new(
1196 Url::parse("http://example.com/").unwrap(),
1197 &[],
1198 ))
1199 .unwrap();
1200 assert_eq!(url.query(), Some("ids=1&ids=2&ids=3"));
1201 }
1202
1203 #[test]
1204 fn test_array_form_non_exploded() {
1205 #[derive(Serialize)]
1206 struct Q {
1207 ids: Vec<i32>,
1208 }
1209
1210 let url = Q { ids: vec![1, 2, 3] }
1211 .serialize(QuerySerializer::new(
1212 Url::parse("http://example.com/").unwrap(),
1213 &[("ids", QueryStyle::Form { exploded: false })],
1214 ))
1215 .unwrap();
1216 assert_eq!(url.query(), Some("ids=1,2,3"));
1217 }
1218
1219 #[test]
1220 fn test_array_space_delimited() {
1221 #[derive(Serialize)]
1222 struct Q {
1223 ids: Vec<i32>,
1224 }
1225
1226 let url = Q { ids: vec![1, 2, 3] }
1227 .serialize(QuerySerializer::new(
1228 Url::parse("http://example.com/").unwrap(),
1229 &[("ids", QueryStyle::SpaceDelimited)],
1230 ))
1231 .unwrap();
1232 assert_eq!(url.query(), Some("ids=1%202%203"));
1233 }
1234
1235 #[test]
1236 fn test_array_pipe_delimited() {
1237 #[derive(Serialize)]
1238 struct Q {
1239 ids: Vec<i32>,
1240 }
1241
1242 let url = Q { ids: vec![1, 2, 3] }
1243 .serialize(QuerySerializer::new(
1244 Url::parse("http://example.com/").unwrap(),
1245 &[("ids", QueryStyle::PipeDelimited)],
1246 ))
1247 .unwrap();
1248 assert_eq!(url.query(), Some("ids=1%7C2%7C3"));
1249 }
1250
1251 #[test]
1252 fn test_empty_array() {
1253 #[derive(Serialize)]
1254 struct Q {
1255 ids: Vec<i32>,
1256 }
1257
1258 let url = Q { ids: vec![] }
1259 .serialize(QuerySerializer::new(
1260 Url::parse("http://example.com/").unwrap(),
1261 &[],
1262 ))
1263 .unwrap();
1264 assert_eq!(url.query(), None);
1265 }
1266
1267 #[test]
1268 fn test_array_of_strings_with_special_chars() {
1269 #[derive(Serialize)]
1270 struct Q {
1271 tags: Vec<&'static str>,
1272 }
1273
1274 let url = Q {
1275 tags: vec!["hello world", "foo&bar"],
1276 }
1277 .serialize(QuerySerializer::new(
1278 Url::parse("http://example.com/").unwrap(),
1279 &[("tags", QueryStyle::Form { exploded: false })],
1280 ))
1281 .unwrap();
1282 assert_eq!(url.query(), Some("tags=hello%20world,foo%26bar"));
1283 }
1284
1285 #[test]
1286 fn test_deep_object_rejects_top_level_arrays() {
1287 #[derive(Serialize)]
1288 struct Q {
1289 ids: Vec<i32>,
1290 }
1291
1292 let result = Q { ids: vec![1, 2, 3] }.serialize(QuerySerializer::new(
1293 Url::parse("http://example.com/").unwrap(),
1294 &[("ids", QueryStyle::DeepObject)],
1295 ));
1296 assert!(matches!(
1297 result,
1298 Err(QueryParamError::UnspecifiedStyleExploded)
1299 ));
1300 }
1301
1302 #[test]
1305 fn test_tuple_form_exploded() {
1306 #[derive(Serialize)]
1307 struct Q {
1308 coords: (i32, i32, i32),
1309 }
1310
1311 let url = Q {
1312 coords: (42, 24, 10),
1313 }
1314 .serialize(QuerySerializer::new(
1315 Url::parse("http://example.com/").unwrap(),
1316 &[],
1317 ))
1318 .unwrap();
1319 assert_eq!(url.query(), Some("coords=42&coords=24&coords=10"));
1320 }
1321
1322 #[test]
1323 fn test_tuple_form_non_exploded() {
1324 #[derive(Serialize)]
1325 struct Q {
1326 coords: (i32, i32, i32),
1327 }
1328
1329 let url = Q {
1330 coords: (42, 24, 10),
1331 }
1332 .serialize(QuerySerializer::new(
1333 Url::parse("http://example.com/").unwrap(),
1334 &[("coords", QueryStyle::Form { exploded: false })],
1335 ))
1336 .unwrap();
1337 assert_eq!(url.query(), Some("coords=42,24,10"));
1338 }
1339
1340 #[test]
1341 fn test_tuple_space_delimited() {
1342 #[derive(Serialize)]
1343 struct Q {
1344 coords: (i32, i32, i32),
1345 }
1346
1347 let url = Q {
1348 coords: (42, 24, 10),
1349 }
1350 .serialize(QuerySerializer::new(
1351 Url::parse("http://example.com/").unwrap(),
1352 &[("coords", QueryStyle::SpaceDelimited)],
1353 ))
1354 .unwrap();
1355 assert_eq!(url.query(), Some("coords=42%2024%2010"));
1356 }
1357
1358 #[test]
1359 fn test_tuple_pipe_delimited() {
1360 #[derive(Serialize)]
1361 struct Q {
1362 coords: (i32, i32, i32),
1363 }
1364
1365 let url = Q {
1366 coords: (42, 24, 10),
1367 }
1368 .serialize(QuerySerializer::new(
1369 Url::parse("http://example.com/").unwrap(),
1370 &[("coords", QueryStyle::PipeDelimited)],
1371 ))
1372 .unwrap();
1373 assert_eq!(url.query(), Some("coords=42%7C24%7C10"));
1374 }
1375
1376 #[test]
1379 fn test_object_form_exploded() {
1380 #[derive(Serialize)]
1381 struct Q {
1382 first_name: String,
1383 last_name: String,
1384 }
1385
1386 let url = Q {
1387 first_name: "John".to_owned(),
1388 last_name: "Doe".to_owned(),
1389 }
1390 .serialize(QuerySerializer::new(
1391 Url::parse("http://example.com/").unwrap(),
1392 &[
1393 ("first_name", QueryStyle::Form { exploded: true }),
1394 ("last_name", QueryStyle::Form { exploded: true }),
1395 ],
1396 ))
1397 .unwrap();
1398 assert_eq!(url.query(), Some("first_name=John&last_name=Doe"));
1399 }
1400
1401 #[test]
1402 fn test_object_form_non_exploded() {
1403 #[derive(Serialize)]
1404 struct Person {
1405 first_name: String,
1406 last_name: String,
1407 }
1408
1409 #[derive(Serialize)]
1410 struct Q {
1411 person: Person,
1412 }
1413
1414 let url = Q {
1415 person: Person {
1416 first_name: "John".to_owned(),
1417 last_name: "Doe".to_owned(),
1418 },
1419 }
1420 .serialize(QuerySerializer::new(
1421 Url::parse("http://example.com/").unwrap(),
1422 &[("person", QueryStyle::Form { exploded: false })],
1423 ))
1424 .unwrap();
1425 assert_eq!(url.query(), Some("person=first_name,John,last_name,Doe"));
1426 }
1427
1428 #[test]
1429 fn test_object_deep_object() {
1430 #[derive(Serialize)]
1431 struct Filter {
1432 #[serde(rename = "type")]
1433 type_field: String,
1434 location: String,
1435 }
1436
1437 #[derive(Serialize)]
1438 struct Q {
1439 filter: Filter,
1440 }
1441
1442 let url = Q {
1443 filter: Filter {
1444 type_field: "cocktail".to_owned(),
1445 location: "bar".to_owned(),
1446 },
1447 }
1448 .serialize(QuerySerializer::new(
1449 Url::parse("http://example.com/").unwrap(),
1450 &[("filter", QueryStyle::DeepObject)],
1451 ))
1452 .unwrap();
1453 assert_eq!(
1454 url.query(),
1455 Some("filter%5Btype%5D=cocktail&filter%5Blocation%5D=bar")
1456 );
1457 }
1458
1459 #[test]
1460 fn test_space_delimited_object() {
1461 #[derive(Serialize)]
1462 struct Color {
1463 r: u32,
1464 g: u32,
1465 b: u32,
1466 }
1467
1468 #[derive(Serialize)]
1469 struct Q {
1470 color: Color,
1471 }
1472
1473 let url = Q {
1474 color: Color {
1475 r: 100,
1476 g: 200,
1477 b: 150,
1478 },
1479 }
1480 .serialize(QuerySerializer::new(
1481 Url::parse("http://example.com/").unwrap(),
1482 &[("color", QueryStyle::SpaceDelimited)],
1483 ))
1484 .unwrap();
1485 assert_eq!(url.query(), Some("color=r%20100%20g%20200%20b%20150"));
1486 }
1487
1488 #[test]
1489 fn test_pipe_delimited_object() {
1490 #[derive(Serialize)]
1491 struct Color {
1492 r: u32,
1493 g: u32,
1494 b: u32,
1495 }
1496
1497 #[derive(Serialize)]
1498 struct Q {
1499 color: Color,
1500 }
1501
1502 let url = Q {
1503 color: Color {
1504 r: 100,
1505 g: 200,
1506 b: 150,
1507 },
1508 }
1509 .serialize(QuerySerializer::new(
1510 Url::parse("http://example.com/").unwrap(),
1511 &[("color", QueryStyle::PipeDelimited)],
1512 ))
1513 .unwrap();
1514 assert_eq!(url.query(), Some("color=r%7C100%7Cg%7C200%7Cb%7C150"));
1515 }
1516
1517 #[test]
1518 fn test_nested_deep_object() {
1519 #[derive(Serialize)]
1520 struct Address {
1521 city: String,
1522 country: String,
1523 }
1524
1525 #[derive(Serialize)]
1526 struct Person {
1527 name: String,
1528 address: Address,
1529 }
1530
1531 #[derive(Serialize)]
1532 struct Q {
1533 person: Person,
1534 }
1535
1536 let url = Q {
1537 person: Person {
1538 name: "Alice".to_owned(),
1539 address: Address {
1540 city: "Paris".to_owned(),
1541 country: "France".to_owned(),
1542 },
1543 },
1544 }
1545 .serialize(QuerySerializer::new(
1546 Url::parse("http://example.com/").unwrap(),
1547 &[("person", QueryStyle::DeepObject)],
1548 ))
1549 .unwrap();
1550 assert_eq!(
1551 url.query(),
1552 Some(
1553 "person%5Bname%5D=Alice&person%5Baddress%5D%5Bcity%5D=Paris&person%5Baddress%5D%5Bcountry%5D=France"
1554 )
1555 );
1556 }
1557
1558 #[test]
1559 fn test_deep_object_with_array_field() {
1560 #[derive(Serialize)]
1561 struct Filter {
1562 category: String,
1563 tags: Vec<String>,
1564 }
1565
1566 #[derive(Serialize)]
1567 struct Q {
1568 filter: Filter,
1569 }
1570
1571 let url = Q {
1572 filter: Filter {
1573 category: "electronics".to_owned(),
1574 tags: vec!["new".to_owned(), "sale".to_owned()],
1575 },
1576 }
1577 .serialize(QuerySerializer::new(
1578 Url::parse("http://example.com/").unwrap(),
1579 &[("filter", QueryStyle::DeepObject)],
1580 ))
1581 .unwrap();
1582 assert_eq!(
1583 url.query(),
1584 Some(
1585 "filter%5Bcategory%5D=electronics&filter%5Btags%5D%5B0%5D=new&filter%5Btags%5D%5B1%5D=sale"
1586 )
1587 );
1588 }
1589
1590 #[test]
1593 fn test_multiple_params() {
1594 #[derive(Serialize)]
1595 struct Q {
1596 limit: i32,
1597 tags: Vec<&'static str>,
1598 }
1599
1600 let url = Q {
1601 limit: 10,
1602 tags: vec!["dog", "cat"],
1603 }
1604 .serialize(QuerySerializer::new(
1605 Url::parse("http://example.com/").unwrap(),
1606 &[
1607 ("limit", QueryStyle::Form { exploded: true }),
1608 ("tags", QueryStyle::Form { exploded: true }),
1609 ],
1610 ))
1611 .unwrap();
1612 assert_eq!(url.query(), Some("limit=10&tags=dog&tags=cat"));
1613 }
1614
1615 #[test]
1616 fn test_serde_skip_if() {
1617 #[derive(Serialize)]
1618 struct Q {
1619 required: i32,
1620 #[serde(skip_serializing_if = "Option::is_none")]
1621 optional: Option<String>,
1622 }
1623
1624 let url = Q {
1625 required: 42,
1626 optional: None,
1627 }
1628 .serialize(QuerySerializer::new(
1629 Url::parse("http://example.com/").unwrap(),
1630 &[
1631 ("required", QueryStyle::Form { exploded: true }),
1632 ("optional", QueryStyle::Form { exploded: true }),
1633 ],
1634 ))
1635 .unwrap();
1636 assert_eq!(url.query(), Some("required=42"));
1637 }
1638
1639 #[test]
1640 fn test_mixed_styles() {
1641 #[derive(Serialize)]
1642 struct Filter {
1643 #[serde(rename = "type")]
1644 type_field: String,
1645 }
1646
1647 #[derive(Serialize)]
1648 struct Q {
1649 filter: Filter,
1650 limit: i32,
1651 }
1652
1653 let url = Q {
1654 filter: Filter {
1655 type_field: "cocktail".to_owned(),
1656 },
1657 limit: 10,
1658 }
1659 .serialize(QuerySerializer::new(
1660 Url::parse("http://example.com/").unwrap(),
1661 &[
1662 ("filter", QueryStyle::DeepObject),
1663 ("limit", QueryStyle::Form { exploded: true }),
1664 ],
1665 ))
1666 .unwrap();
1667 assert_eq!(url.query(), Some("filter%5Btype%5D=cocktail&limit=10"));
1668 }
1669
1670 #[test]
1671 fn test_unlisted_field_uses_default_style() {
1672 #[derive(Serialize)]
1673 struct Q {
1674 limit: i32,
1675 }
1676
1677 let url = Q { limit: 42 }
1680 .serialize(QuerySerializer::new(
1681 Url::parse("http://example.com/").unwrap(),
1682 &[],
1683 ))
1684 .unwrap();
1685 assert_eq!(url.query(), Some("limit=42"));
1686 }
1687}