use rattler_conda_types::{Channel, ChannelConfig};
use serde::de::Error;
use serde::{Deserialize, Deserializer};
use serde_with::serde_as;
use std::borrow::Cow;
#[serde_as]
#[derive(Debug, Clone, PartialEq, Eq, Hash, Deserialize)]
pub struct PrioritizedChannel {
#[serde_as(as = "ChannelStr")]
pub channel: Channel,
pub priority: Option<i32>,
}
impl PrioritizedChannel {
pub fn from_channel(channel: Channel) -> Self {
Self {
channel,
priority: None,
}
}
}
pub enum TomlPrioritizedChannelStrOrMap {
Map(PrioritizedChannel),
Str(Channel),
}
impl TomlPrioritizedChannelStrOrMap {
pub fn into_prioritized_channel(self) -> PrioritizedChannel {
match self {
TomlPrioritizedChannelStrOrMap::Map(prioritized_channel) => prioritized_channel,
TomlPrioritizedChannelStrOrMap::Str(channel) => {
PrioritizedChannel::from_channel(channel)
}
}
}
}
impl<'de> Deserialize<'de> for TomlPrioritizedChannelStrOrMap {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
serde_untagged::UntaggedEnumVisitor::new()
.map(|map| map.deserialize().map(TomlPrioritizedChannelStrOrMap::Map))
.string(|str| {
Channel::from_str(str, &ChannelConfig::default())
.map(TomlPrioritizedChannelStrOrMap::Str)
.map_err(serde::de::Error::custom)
})
.expecting("either a map or a string")
.deserialize(deserializer)
}
}
impl<'de> serde_with::DeserializeAs<'de, PrioritizedChannel> for TomlPrioritizedChannelStrOrMap {
fn deserialize_as<D>(deserializer: D) -> Result<PrioritizedChannel, D::Error>
where
D: Deserializer<'de>,
{
let prioritized_channel = TomlPrioritizedChannelStrOrMap::deserialize(deserializer)?;
Ok(prioritized_channel.into_prioritized_channel())
}
}
pub struct ChannelStr;
impl<'de> serde_with::DeserializeAs<'de, Channel> for ChannelStr {
fn deserialize_as<D>(deserializer: D) -> Result<Channel, D::Error>
where
D: Deserializer<'de>,
{
let channel_str = Cow::<str>::deserialize(deserializer)?;
let channel_config = ChannelConfig::default();
Channel::from_str(channel_str, &channel_config).map_err(D::Error::custom)
}
}