use super::{QueryError, QueryList, QueryValue, ValueContext};
#[derive(Clone, Copy, Debug)]
pub struct QueryMap<'a> {
pub(super) entries: QueryList<'a>,
}
impl<'a> QueryMap<'a> {
pub fn new(entries: QueryList<'a>, context: &mut ValueContext<'_>) -> Result<Self, QueryError> {
QueryValue::List(entries).validate(context)?;
if !entries.len().is_multiple_of(2) {
return Err(QueryError::Type);
}
let mut previous: Option<&str> = None;
for i in (0..entries.len()).step_by(2) {
context.step()?;
let Some(QueryValue::String(key)) = entries.get(i) else {
return Err(QueryError::Type);
};
if let Some(old) = previous
&& super::value::compare_bytes(old.as_bytes(), key.as_bytes(), context)?
!= std::cmp::Ordering::Less
{
return Err(QueryError::Type);
}
previous = Some(key);
}
Ok(Self { entries })
}
pub const fn len(self) -> usize {
self.entries.len() / 2
}
pub const fn is_empty(self) -> bool {
self.len() == 0
}
pub const fn entries(self) -> QueryList<'a> {
self.entries
}
pub fn get(
self,
key: &str,
context: &mut ValueContext<'_>,
) -> Result<QueryValue<'a>, QueryError> {
for i in (0..self.entries.len()).step_by(2) {
context.step()?;
let Some(QueryValue::String(name)) = self.entries.get(i) else {
return Err(QueryError::Type);
};
if super::value::compare_bytes(name.as_bytes(), key.as_bytes(), context)?
== std::cmp::Ordering::Equal
{
return self.entries.get(i + 1).ok_or(QueryError::Type);
}
}
Ok(QueryValue::Null)
}
}