1#[derive(Debug, Clone, PartialEq, Eq)]
13pub enum Payload {
14 Json(serde_json::Value),
16 Raw(Vec<u8>),
18 Multipart(Vec<Part>),
20}
21
22#[derive(Debug, Clone, PartialEq, Eq)]
24pub struct Part {
25 name: String,
26 filename: Option<String>,
27 bytes: Vec<u8>,
28}
29
30impl Part {
31 #[must_use]
33 pub fn text(name: impl Into<String>, value: impl Into<String>) -> Self {
34 Self {
35 name: name.into(),
36 filename: None,
37 bytes: value.into().into_bytes(),
38 }
39 }
40
41 #[must_use]
43 pub fn file(name: impl Into<String>, filename: impl Into<String>, bytes: Vec<u8>) -> Self {
44 Self {
45 name: name.into(),
46 filename: Some(filename.into()),
47 bytes,
48 }
49 }
50
51 #[must_use]
52 pub fn name(&self) -> &str {
53 &self.name
54 }
55
56 #[must_use]
57 pub fn filename(&self) -> Option<&str> {
58 self.filename.as_deref()
59 }
60
61 #[must_use]
62 pub fn bytes(&self) -> &[u8] {
63 &self.bytes
64 }
65}
66
67#[derive(Debug, Clone, Default, PartialEq, Eq)]
75pub struct Values {
76 params: Vec<(String, String)>,
77 body: Option<Payload>,
78}
79
80impl Values {
81 #[must_use]
82 pub fn new() -> Self {
83 Self::default()
84 }
85
86 #[must_use]
88 #[expect(
89 clippy::needless_pass_by_value,
90 reason = "taking a reference would put `&` in front of every argument \
91 at every generated call site, for values that cost nothing to move"
92 )]
93 pub fn param(mut self, name: impl Into<String>, value: impl ToString) -> Self {
94 self.params.push((name.into(), value.to_string()));
95 self
96 }
97
98 #[must_use]
100 pub fn maybe(self, name: impl Into<String>, value: Option<impl ToString>) -> Self {
101 match value {
102 Some(value) => self.param(name, value),
103 None => self,
104 }
105 }
106
107 #[must_use]
115 pub fn each(
116 mut self,
117 name: impl Into<String>,
118 values: impl IntoIterator<Item = impl ToString>,
119 ) -> Self {
120 let name = name.into();
121 for value in values {
122 self.params.push((name.clone(), value.to_string()));
123 }
124 self
125 }
126
127 #[must_use]
128 pub fn json(mut self, value: serde_json::Value) -> Self {
129 self.body = Some(Payload::Json(value));
130 self
131 }
132
133 #[must_use]
134 pub fn raw(mut self, bytes: Vec<u8>) -> Self {
135 self.body = Some(Payload::Raw(bytes));
136 self
137 }
138
139 #[must_use]
140 pub fn multipart(mut self, parts: Vec<Part>) -> Self {
141 self.body = Some(Payload::Multipart(parts));
142 self
143 }
144
145 #[must_use]
147 pub fn body(mut self, body: Option<Payload>) -> Self {
148 if let Some(body) = body {
149 self.body = Some(body);
150 }
151 self
152 }
153
154 #[must_use]
155 pub fn params(&self) -> &[(String, String)] {
156 &self.params
157 }
158
159 #[must_use]
160 pub fn payload(&self) -> Option<&Payload> {
161 self.body.as_ref()
162 }
163}