use alloc::{collections::TryReserveError, string::String, vec::Vec};
use core::{
cmp::Ordering,
fmt::{Debug, Display},
ops::{Deref, DerefMut},
};
use super::{Attribute, Name};
pub trait Storage: Copy {
type Label: Debug + Display;
type Refusal: Debug + Display;
type Attributes<'a>: AttributeBuffer<'a, Self>;
fn attributes<'a>(&self) -> Self::Attributes<'a>;
fn admit(&self, units: usize) -> Result<(), Self::Refusal>;
fn qualified_name(&self, name: Name<'_>) -> Result<Self::Label, Self::Refusal>;
}
pub trait AttributeBuffer<'a, S: Storage>: Deref<Target = [Attribute<'a>]> + DerefMut {
fn push(&mut self, attribute: Attribute<'a>) -> Result<(), S::Refusal>;
fn sort(
&mut self,
compare: impl FnMut(&Attribute<'a>, &Attribute<'a>) -> Result<Ordering, S::Refusal>,
) -> Result<(), S::Refusal>;
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct Native;
impl Storage for Native {
type Label = String;
type Refusal = TryReserveError;
type Attributes<'a> = Vec<Attribute<'a>>;
fn attributes<'a>(&self) -> Self::Attributes<'a> {
Vec::new()
}
fn admit(&self, _: usize) -> Result<(), TryReserveError> {
Ok(())
}
fn qualified_name(&self, name: Name<'_>) -> Result<String, TryReserveError> {
let mut label = String::new();
label.try_reserve_exact(
name.prefix.len() + name.local.len() + usize::from(!name.prefix.is_empty()),
)?;
if !name.prefix.is_empty() {
label.push_str(name.prefix);
label.push(':');
}
label.push_str(name.local);
Ok(label)
}
}
impl<'a, S: Storage<Refusal = TryReserveError>> AttributeBuffer<'a, S> for Vec<Attribute<'a>> {
fn push(&mut self, attribute: Attribute<'a>) -> Result<(), TryReserveError> {
self.try_reserve(1)?;
Vec::push(self, attribute);
Ok(())
}
fn sort(
&mut self,
mut compare: impl FnMut(&Attribute<'a>, &Attribute<'a>) -> Result<Ordering, TryReserveError>,
) -> Result<(), TryReserveError> {
let mut failure = None;
self.sort_unstable_by(|left, right| {
if failure.is_some() {
return Ordering::Equal;
}
match compare(left, right) {
Ok(ordering) => ordering,
Err(error) => {
failure = Some(error);
Ordering::Equal
}
}
});
match failure {
Some(error) => Err(error),
None => Ok(()),
}
}
}