#[derive(Debug, Clone, PartialEq, Eq)]
pub enum Payload {
Json(serde_json::Value),
Raw(Vec<u8>),
Multipart(Vec<Part>),
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Part {
name: String,
filename: Option<String>,
bytes: Vec<u8>,
}
impl Part {
#[must_use]
pub fn text(name: impl Into<String>, value: impl Into<String>) -> Self {
Self {
name: name.into(),
filename: None,
bytes: value.into().into_bytes(),
}
}
#[must_use]
pub fn file(name: impl Into<String>, filename: impl Into<String>, bytes: Vec<u8>) -> Self {
Self {
name: name.into(),
filename: Some(filename.into()),
bytes,
}
}
#[must_use]
pub fn name(&self) -> &str {
&self.name
}
#[must_use]
pub fn filename(&self) -> Option<&str> {
self.filename.as_deref()
}
#[must_use]
pub fn bytes(&self) -> &[u8] {
&self.bytes
}
}
#[derive(Debug, Clone, Default, PartialEq, Eq)]
pub struct Values {
params: Vec<(String, String)>,
body: Option<Payload>,
}
impl Values {
#[must_use]
pub fn new() -> Self {
Self::default()
}
#[must_use]
#[expect(
clippy::needless_pass_by_value,
reason = "taking a reference would put `&` in front of every argument \
at every generated call site, for values that cost nothing to move"
)]
pub fn param(mut self, name: impl Into<String>, value: impl ToString) -> Self {
self.params.push((name.into(), value.to_string()));
self
}
#[must_use]
pub fn maybe(self, name: impl Into<String>, value: Option<impl ToString>) -> Self {
match value {
Some(value) => self.param(name, value),
None => self,
}
}
#[must_use]
pub fn each(
mut self,
name: impl Into<String>,
values: impl IntoIterator<Item = impl ToString>,
) -> Self {
let name = name.into();
for value in values {
self.params.push((name.clone(), value.to_string()));
}
self
}
#[must_use]
pub fn json(mut self, value: serde_json::Value) -> Self {
self.body = Some(Payload::Json(value));
self
}
#[must_use]
pub fn raw(mut self, bytes: Vec<u8>) -> Self {
self.body = Some(Payload::Raw(bytes));
self
}
#[must_use]
pub fn multipart(mut self, parts: Vec<Part>) -> Self {
self.body = Some(Payload::Multipart(parts));
self
}
#[must_use]
pub fn body(mut self, body: Option<Payload>) -> Self {
if let Some(body) = body {
self.body = Some(body);
}
self
}
#[must_use]
pub fn params(&self) -> &[(String, String)] {
&self.params
}
#[must_use]
pub fn payload(&self) -> Option<&Payload> {
self.body.as_ref()
}
}