use std::{cmp, fmt, ops};
use crate::parsers::hcl::{
Pair, Rule,
ast::{Str, expr::Expression},
};
#[derive(Clone)]
pub struct Object<'i>(Vec<(ObjectKey<'i>, Expression<'i>)>);
impl<'i> Object<'i> {
pub fn get_by_name(&self, name: &str) -> Option<&Expression<'i>> {
self.iter()
.find_map(|(key, value)| if key == name { Some(value) } else { None })
}
}
impl<'i> Object<'i> {
pub(super) fn process(pair: Pair<'i>) -> Self {
let mut items = pair.into_inner();
let mut data = Vec::with_capacity(items.size_hint().0 / 2);
while let Some(key) = items.next() {
let key = ObjectKey::process(key);
let value = items.next().unwrap();
let value = Expression::process(value);
data.push((key, value));
}
Self(data)
}
}
impl<'i> ops::Deref for Object<'i> {
type Target = [(ObjectKey<'i>, Expression<'i>)];
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl fmt::Debug for Object<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_map()
.entries(self.0.iter().map(|(key, val)| (key, val)))
.finish()
}
}
#[derive(Debug, Clone)]
pub enum ObjectKey<'i> {
Ident(Str<'i>),
Expr(Expression<'i>),
}
impl<'i> ObjectKey<'i> {
pub fn as_ident(&self) -> Option<Str<'i>> {
if let Self::Ident(s) = self {
Some(*s)
} else {
None
}
}
pub fn as_expr(&self) -> Option<&Expression<'i>> {
if let Self::Expr(v) = self {
Some(v)
} else {
None
}
}
}
impl<'i> ObjectKey<'i> {
fn process(pair: Pair<'i>) -> Self {
match pair.as_rule() {
Rule::Identifier => ObjectKey::Ident(Str::from(pair)),
Rule::Expression => ObjectKey::Expr(Expression::process(pair)),
rule => unreachable!("{rule:?}"),
}
}
}
impl cmp::PartialEq<str> for ObjectKey<'_> {
fn eq(&self, other: &str) -> bool {
self.as_ident().is_some_and(|id| id == other)
}
}