use crate::expr::Expression;
use crate::{Decor, Decorate, Decorated, Ident, RawString, Span};
use std::ops::{self, Range};
use vecmap::map::{MutableKeys, VecMap};
pub type ObjectIntoIter = Box<dyn Iterator<Item = (ObjectKey, ObjectValue)>>;
pub type ObjectIter<'a> = Box<dyn Iterator<Item = (&'a ObjectKey, &'a ObjectValue)> + 'a>;
pub type ObjectIterMut<'a> = Box<dyn Iterator<Item = (ObjectKeyMut<'a>, &'a mut ObjectValue)> + 'a>;
#[derive(Debug, Clone, Eq, Default)]
pub struct Object {
items: VecMap<ObjectKey, ObjectValue>,
trailing: RawString,
decor: Decor,
span: Option<Range<usize>>,
}
impl Object {
#[inline]
pub fn new() -> Self {
Object::default()
}
#[inline]
pub fn with_capacity(capacity: usize) -> Self {
Object {
items: VecMap::with_capacity(capacity),
..Default::default()
}
}
#[inline]
pub fn is_empty(&self) -> bool {
self.items.is_empty()
}
#[inline]
pub fn len(&self) -> usize {
self.items.len()
}
#[inline]
pub fn clear(&mut self) {
self.items.clear();
}
#[inline]
pub fn contains_key(&self, key: &ObjectKey) -> bool {
self.items.contains_key(key)
}
#[inline]
pub fn get(&self, key: &ObjectKey) -> Option<&ObjectValue> {
self.items.get(key)
}
#[inline]
pub fn get_mut(&mut self, key: &ObjectKey) -> Option<&mut ObjectValue> {
self.items.get_mut(key)
}
#[inline]
pub fn get_key_value(&self, key: &ObjectKey) -> Option<(&ObjectKey, &ObjectValue)> {
self.items.get_key_value(key)
}
#[inline]
pub fn get_key_value_mut<'a>(
&'a mut self,
key: &ObjectKey,
) -> Option<(ObjectKeyMut<'a>, &'a mut ObjectValue)> {
self.items
.get_full_mut2(key)
.map(|(_, k, v)| (ObjectKeyMut::new(k), v))
}
#[inline]
pub fn insert(
&mut self,
key: impl Into<ObjectKey>,
value: impl Into<ObjectValue>,
) -> Option<ObjectValue> {
self.items.insert(key.into(), value.into())
}
#[inline]
pub fn remove(&mut self, key: &ObjectKey) -> Option<ObjectValue> {
self.items.remove(key)
}
#[inline]
pub fn remove_entry(&mut self, key: &ObjectKey) -> Option<(ObjectKey, ObjectValue)> {
self.items.remove_entry(key)
}
#[inline]
pub fn iter(&self) -> ObjectIter<'_> {
Box::new(self.items.iter())
}
#[inline]
pub fn iter_mut(&mut self) -> ObjectIterMut<'_> {
Box::new(
self.items
.iter_mut2()
.map(|(k, v)| (ObjectKeyMut::new(k), v)),
)
}
#[inline]
pub fn trailing(&self) -> &RawString {
&self.trailing
}
#[inline]
pub fn set_trailing(&mut self, trailing: impl Into<RawString>) {
self.trailing = trailing.into();
}
pub(crate) fn despan(&mut self, input: &str) {
self.decor.despan(input);
self.trailing.despan(input);
for (key, value) in self.items.iter_mut2() {
key.despan(input);
value.despan(input);
}
}
}
impl PartialEq for Object {
fn eq(&self, other: &Self) -> bool {
self.items == other.items && self.trailing == other.trailing
}
}
impl From<VecMap<ObjectKey, ObjectValue>> for Object {
fn from(items: VecMap<ObjectKey, ObjectValue>) -> Self {
Object {
items,
..Default::default()
}
}
}
impl<K, V> Extend<(K, V)> for Object
where
K: Into<ObjectKey>,
V: Into<ObjectValue>,
{
fn extend<I>(&mut self, iterable: I)
where
I: IntoIterator<Item = (K, V)>,
{
let iter = iterable.into_iter();
let reserve = if self.is_empty() {
iter.size_hint().0
} else {
(iter.size_hint().0 + 1) / 2
};
self.items.reserve(reserve);
iter.for_each(|(k, v)| {
self.insert(k, v);
});
}
}
impl<K, V> FromIterator<(K, V)> for Object
where
K: Into<ObjectKey>,
V: Into<ObjectValue>,
{
fn from_iter<I>(iterable: I) -> Self
where
I: IntoIterator<Item = (K, V)>,
{
let iter = iterable.into_iter();
let lower = iter.size_hint().0;
let mut object = Object::with_capacity(lower);
object.extend(iter);
object
}
}
impl IntoIterator for Object {
type Item = (ObjectKey, ObjectValue);
type IntoIter = ObjectIntoIter;
fn into_iter(self) -> Self::IntoIter {
Box::new(self.items.into_iter())
}
}
impl<'a> IntoIterator for &'a Object {
type Item = (&'a ObjectKey, &'a ObjectValue);
type IntoIter = ObjectIter<'a>;
fn into_iter(self) -> Self::IntoIter {
self.iter()
}
}
impl<'a> IntoIterator for &'a mut Object {
type Item = (ObjectKeyMut<'a>, &'a mut ObjectValue);
type IntoIter = ObjectIterMut<'a>;
fn into_iter(self) -> Self::IntoIter {
self.iter_mut()
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum ObjectKey {
Ident(Decorated<Ident>),
Expression(Expression),
}
impl ObjectKey {
pub fn is_ident(&self) -> bool {
self.as_ident().is_some()
}
pub fn as_ident(&self) -> Option<&Ident> {
match self {
ObjectKey::Ident(value) => Some(value.value()),
ObjectKey::Expression(_) => None,
}
}
pub fn is_expr(&self) -> bool {
self.as_expr().is_some()
}
pub fn as_expr(&self) -> Option<&Expression> {
match self {
ObjectKey::Expression(value) => Some(value),
ObjectKey::Ident(_) => None,
}
}
pub(crate) fn despan(&mut self, input: &str) {
match self {
ObjectKey::Ident(ident) => ident.decor_mut().despan(input),
ObjectKey::Expression(expr) => expr.despan(input),
}
}
}
impl From<Decorated<Ident>> for ObjectKey {
fn from(ident: Decorated<Ident>) -> Self {
ObjectKey::Ident(ident)
}
}
impl From<Ident> for ObjectKey {
fn from(ident: Ident) -> Self {
ObjectKey::from(Decorated::new(ident))
}
}
impl From<Expression> for ObjectKey {
fn from(expr: Expression) -> Self {
ObjectKey::Expression(expr)
}
}
#[derive(Debug, Eq, PartialEq)]
pub struct ObjectKeyMut<'k> {
key: &'k mut ObjectKey,
}
impl<'k> ObjectKeyMut<'k> {
pub(crate) fn new(key: &'k mut ObjectKey) -> ObjectKeyMut<'k> {
ObjectKeyMut { key }
}
pub fn get(&self) -> &ObjectKey {
self.key
}
}
impl<'k> ops::Deref for ObjectKeyMut<'k> {
type Target = ObjectKey;
fn deref(&self) -> &Self::Target {
self.get()
}
}
impl<'k> Decorate for ObjectKeyMut<'k> {
fn decor(&self) -> &Decor {
self.key.decor()
}
fn decor_mut(&mut self) -> &mut Decor {
self.key.decor_mut()
}
}
impl<'k> Span for ObjectKeyMut<'k> {
fn span(&self) -> Option<Range<usize>> {
self.key.span()
}
}
#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)]
pub enum ObjectValueAssignment {
Colon,
#[default]
Equals,
}
#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)]
pub enum ObjectValueTerminator {
None,
Newline,
#[default]
Comma,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct ObjectValue {
expr: Expression,
assignment: ObjectValueAssignment,
terminator: ObjectValueTerminator,
}
impl ObjectValue {
pub fn new(expr: impl Into<Expression>) -> ObjectValue {
ObjectValue {
expr: expr.into(),
assignment: ObjectValueAssignment::default(),
terminator: ObjectValueTerminator::default(),
}
}
pub fn expr(&self) -> &Expression {
&self.expr
}
pub fn expr_mut(&mut self) -> &mut Expression {
&mut self.expr
}
pub fn into_expr(self) -> Expression {
self.expr
}
pub fn assignment(&self) -> ObjectValueAssignment {
self.assignment
}
pub fn set_assignment(&mut self, sep: ObjectValueAssignment) {
self.assignment = sep;
}
pub fn terminator(&self) -> ObjectValueTerminator {
self.terminator
}
pub fn set_terminator(&mut self, terminator: ObjectValueTerminator) {
self.terminator = terminator;
}
pub(crate) fn despan(&mut self, input: &str) {
self.expr.despan(input);
}
}
impl From<Expression> for ObjectValue {
fn from(expr: Expression) -> Self {
ObjectValue::new(expr)
}
}
decorate_impl!(Object);
span_impl!(Object);
forward_decorate_impl!(ObjectKey => { Ident, Expression });
forward_span_impl!(ObjectKey => { Ident, Expression });
#[cfg(test)]
mod tests {
use super::*;
use crate::expr::Array;
use pretty_assertions::assert_eq;
#[test]
fn object_access() {
let mut obj = Object::new();
let mut key = ObjectKey::from(Ident::new("foo"));
key.decorate(("/* prefix */", "/* suffix */"));
let value = ObjectValue::from(Expression::from("bar"));
obj.insert(key.clone(), value.clone());
assert_eq!(obj.get(&key), Some(&value));
key.decor_mut().clear();
assert_eq!(obj.get(&key), Some(&value));
let (key, _) = obj.remove_entry(&key).unwrap();
assert_eq!(key.decor().prefix(), Some(&RawString::from("/* prefix */")));
assert_eq!(key.decor().suffix(), Some(&RawString::from("/* suffix */")));
let mut array = Array::new();
array.push("foo");
let mut key = ObjectKey::from(Expression::from(array));
key.decorate(("/* prefix */", "/* suffix */"));
let value = ObjectValue::from(Expression::from("bar"));
obj.insert(key.clone(), value.clone());
assert_eq!(obj.get(&key), Some(&value));
key.decor_mut().clear();
assert_eq!(obj.get(&key), Some(&value));
let (key, _) = obj.remove_entry(&key).unwrap();
assert_eq!(key.decor().prefix(), Some(&RawString::from("/* prefix */")));
assert_eq!(key.decor().suffix(), Some(&RawString::from("/* suffix */")));
}
}