use strum::IntoEnumIterator;
use crate::error::Error;
use crate::settings::ContainerType;
use crate::{TraitProvision, TypespaceTrait, TypespaceTraitSet};
#[derive(Debug, Clone)]
pub struct Native<Id> {
pub(crate) container: Box<ContainerType>,
pub(crate) parameters: Vec<Id>,
}
impl<Id> Native<Id> {
pub fn path(&self) -> &syn::Type {
self.container.path()
}
pub fn parameters(&self) -> &[Id] {
&self.parameters
}
pub fn obligations(&self) -> &[TypespaceTraitSet] {
self.container.obligations()
}
pub fn disposition(&self, trait_: TypespaceTrait) -> TraitProvision {
self.container.provision(trait_)
}
pub fn dispositions(&self) -> impl Iterator<Item = (TypespaceTrait, TraitProvision)> + '_ {
self.container.provisions()
}
pub fn new(path: &str, impls: TypespaceTraitSet, parameters: Vec<Id>) -> Self {
let always = impls.iter().copied().collect::<Vec<_>>();
let never = TypespaceTrait::iter()
.filter(|tt| !impls.contains(tt))
.collect::<Vec<_>>();
let obligations = vec![TypespaceTraitSet::empty(); parameters.len()];
Self {
container: Box::new(
ContainerType::new(path, obligations).with_provisions(&always, &never),
),
parameters,
}
}
pub fn new_string_like(path: &str) -> Self {
Self::new(
path,
[
TypespaceTrait::Clone,
TypespaceTrait::Debug,
TypespaceTrait::Serialize,
TypespaceTrait::Deserialize,
TypespaceTrait::JsonSchema,
TypespaceTrait::Ord,
TypespaceTrait::PartialOrd,
TypespaceTrait::Eq,
TypespaceTrait::PartialEq,
TypespaceTrait::Hash,
TypespaceTrait::Display,
TypespaceTrait::FromStr,
]
.into_iter()
.collect(),
Vec::new(),
)
}
pub fn with_unknown(self, traits: TypespaceTraitSet) -> Self {
traits.into_iter().fold(self, |native, trait_| {
native.with_disposition(trait_, TraitProvision::Unknown)
})
}
pub fn with_rest_unknown(self) -> Self {
let rest = TypespaceTrait::iter()
.filter(|tt| {
matches!(
self.disposition(*tt),
TraitProvision::Never | TraitProvision::Unknown
)
})
.collect::<TypespaceTraitSet>();
self.with_unknown(rest)
}
pub fn with_disposition(mut self, trait_: TypespaceTrait, disposition: TraitProvision) -> Self {
self.container = Box::new(self.container.with_provision(trait_, disposition));
self
}
pub fn with_obligations(
mut self,
obligations: impl IntoIterator<Item = TypespaceTraitSet>,
) -> Self {
self.container = Box::new(self.container.with_obligations(obligations));
self
}
pub(crate) fn validate(&self) -> Result<(), Error<Id>>
where
Id: std::fmt::Debug + std::fmt::Display,
{
let declared = self.container.obligations().len();
let parameters = self.parameters.len();
if declared != parameters {
return Err(Error::NativeParameterCount {
path: crate::settings::path_text(self.container.path()),
declared,
parameters,
});
}
Ok(())
}
}