use std::ffi::OsString;
use std::os::unix::ffi::{OsStrExt as _, OsStringExt as _};
use serde::de::Error as _;
use serde::{Deserialize, Deserializer, Serialize, Serializer};
pub(super) fn id<S, T>(value: &T, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
T: AsRef<str>,
{
serializer.serialize_str(value.as_ref())
}
pub(super) fn parse_id<'de, D, T>(deserializer: D) -> Result<T, D::Error>
where
D: Deserializer<'de>,
T: std::str::FromStr,
T::Err: std::fmt::Display,
{
let text = String::deserialize(deserializer)?;
text.parse().map_err(D::Error::custom)
}
#[derive(Serialize, Deserialize)]
#[serde(untagged)]
enum Argument {
Text(String),
Bytes(Vec<u8>),
}
pub(super) fn argument<S: Serializer>(value: &OsString, serializer: S) -> Result<S::Ok, S::Error> {
match value.to_str() {
Some(text) => Argument::Text(text.to_owned()),
None => Argument::Bytes(value.as_bytes().to_vec()),
}
.serialize(serializer)
}
pub(super) fn parse_argument<'de, D: Deserializer<'de>>(
deserializer: D,
) -> Result<OsString, D::Error> {
Ok(match Argument::deserialize(deserializer)? {
Argument::Text(text) => OsString::from(text),
Argument::Bytes(bytes) => OsString::from_vec(bytes),
})
}
#[allow(
clippy::ref_option,
reason = "the signature serde's serialize_with requires"
)]
pub(super) fn optional_argument<S: Serializer>(
value: &Option<OsString>,
serializer: S,
) -> Result<S::Ok, S::Error> {
match value {
Some(value) => argument(value, serializer),
None => serializer.serialize_none(),
}
}
pub(super) fn parse_optional_argument<'de, D: Deserializer<'de>>(
deserializer: D,
) -> Result<Option<OsString>, D::Error> {
Ok(
Option::<Argument>::deserialize(deserializer)?.map(|argument| match argument {
Argument::Text(text) => OsString::from(text),
Argument::Bytes(bytes) => OsString::from_vec(bytes),
}),
)
}
pub(super) fn pairs<S: Serializer>(
value: &[(OsString, OsString)],
serializer: S,
) -> Result<S::Ok, S::Error> {
let wire: Vec<(Argument, Argument)> = value
.iter()
.map(|(name, item)| (owned(name), owned(item)))
.collect();
wire.serialize(serializer)
}
pub(super) fn parse_pairs<'de, D: Deserializer<'de>>(
deserializer: D,
) -> Result<Vec<(OsString, OsString)>, D::Error> {
Ok(Vec::<(Argument, Argument)>::deserialize(deserializer)?
.into_iter()
.map(|(name, value)| (borrowed(name), borrowed(value)))
.collect())
}
pub(super) fn list<S: Serializer>(value: &[OsString], serializer: S) -> Result<S::Ok, S::Error> {
value
.iter()
.map(owned)
.collect::<Vec<_>>()
.serialize(serializer)
}
pub(super) fn parse_list<'de, D: Deserializer<'de>>(
deserializer: D,
) -> Result<Vec<OsString>, D::Error> {
Ok(Vec::<Argument>::deserialize(deserializer)?
.into_iter()
.map(borrowed)
.collect())
}
fn owned(value: &OsString) -> Argument {
value.to_str().map_or_else(
|| Argument::Bytes(value.as_bytes().to_vec()),
|text| Argument::Text(text.to_owned()),
)
}
fn borrowed(argument: Argument) -> OsString {
match argument {
Argument::Text(text) => OsString::from(text),
Argument::Bytes(bytes) => OsString::from_vec(bytes),
}
}