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]
108 pub fn json(mut self, value: serde_json::Value) -> Self {
109 self.body = Some(Payload::Json(value));
110 self
111 }
112
113 #[must_use]
114 pub fn raw(mut self, bytes: Vec<u8>) -> Self {
115 self.body = Some(Payload::Raw(bytes));
116 self
117 }
118
119 #[must_use]
120 pub fn multipart(mut self, parts: Vec<Part>) -> Self {
121 self.body = Some(Payload::Multipart(parts));
122 self
123 }
124
125 #[must_use]
127 pub fn body(mut self, body: Option<Payload>) -> Self {
128 if let Some(body) = body {
129 self.body = Some(body);
130 }
131 self
132 }
133
134 #[must_use]
135 pub fn params(&self) -> &[(String, String)] {
136 &self.params
137 }
138
139 #[must_use]
140 pub fn payload(&self) -> Option<&Payload> {
141 self.body.as_ref()
142 }
143}