#![allow(unused_imports)]
use crate::arr::Arr;
use crate::error::OverError;
use crate::parse;
use crate::parse::format::Format;
use crate::tup::Tup;
use crate::types::Type;
use crate::util::{is_digit, write_file_str};
use crate::value::Value;
use crate::{OverResult, INDENT_STEP};
use num_bigint::BigInt;
use num_rational::BigRational;
use num_traits::Zero;
use std::collections::hash_map::{Iter, Keys, Values};
use std::collections::HashMap;
use std::str::FromStr;
use std::sync::atomic::{AtomicUsize, Ordering};
use std::sync::Arc;
use std::{convert, fmt, io};
lazy_static! {
static ref CUR_ID: AtomicUsize = AtomicUsize::new(0);
}
fn get_id() -> usize {
CUR_ID.fetch_add(1, Ordering::Relaxed)
}
#[derive(Clone, Debug)]
struct ObjInner {
map: HashMap<String, Value>,
parent: Option<Obj>,
id: usize,
}
#[derive(Clone, Debug)]
pub struct Obj {
inner: Arc<ObjInner>,
}
macro_rules! get_fn {
( $doc:expr, $name:tt, $type:ty ) => {
#[doc=$doc]
pub fn $name(&self, field: &str) -> OverResult<$type> {
match self.get(field) {
Some(value) => {
match value.$name() {
Ok(result) => Ok(result),
e @ Err(_) => e,
}
}
None => Err(OverError::FieldNotFound(field.into())),
}
}
}
}
impl Obj {
pub fn from_map(obj_map: HashMap<String, Value>) -> OverResult<Obj> {
for field in obj_map.keys() {
if !Self::is_valid_field(field) {
return Err(OverError::InvalidFieldName((*field).clone()));
}
}
let id = get_id();
Ok(Obj {
inner: Arc::new(ObjInner {
map: obj_map,
parent: None,
id,
}),
})
}
pub fn from_map_with_parent(obj_map: HashMap<String, Value>, parent: Obj) -> OverResult<Obj> {
for field in obj_map.keys() {
if !Self::is_valid_field(field) {
return Err(OverError::InvalidFieldName(field.clone()));
}
}
let id = get_id();
Ok(Obj {
inner: Arc::new(ObjInner {
map: obj_map,
parent: Some(parent),
id,
}),
})
}
pub fn from_map_unchecked(obj_map: HashMap<String, Value>) -> Obj {
let id = get_id();
Obj {
inner: Arc::new(ObjInner {
map: obj_map,
parent: None,
id,
}),
}
}
pub fn from_map_with_parent_unchecked(obj_map: HashMap<String, Value>, parent: Obj) -> Obj {
let id = get_id();
Obj {
inner: Arc::new(ObjInner {
map: obj_map,
parent: Some(parent),
id,
}),
}
}
pub fn id(&self) -> usize {
self.inner.id
}
pub fn map_ref(&self) -> &HashMap<String, Value> {
&self.inner.map
}
pub fn from_file(path: &str) -> OverResult<Obj> {
Ok(parse::load_from_file(path)?)
}
pub fn write_to_file(&self, path: &str) -> OverResult<()> {
write_file_str(path, &self.write_str())?;
Ok(())
}
pub fn write_str(&self) -> String {
self.format(false, 0)
}
pub fn with_each<F>(&self, mut f: F)
where
F: FnMut(&String, &Value),
{
for (field, value) in &self.inner.map {
f(field, value)
}
}
pub fn len(&self) -> usize {
self.inner.map.len()
}
pub fn is_empty(&self) -> bool {
self.inner.map.is_empty()
}
pub fn ptr_eq(&self, other: &Self) -> bool {
Arc::ptr_eq(&self.inner, &other.inner)
}
pub fn contains(&self, field: &str) -> bool {
self.inner.map.contains_key(field)
}
pub fn get(&self, field: &str) -> Option<Value> {
match self.inner.map.get(field) {
Some(value) => Some(value.clone()),
None => match self.inner.parent {
Some(ref parent) => parent.get(field),
None => None,
},
}
}
pub fn get_with_source(&self, field: &str) -> Option<(Value, Obj)> {
match self.inner.map.get(field) {
Some(value) => Some((value.clone(), self.clone())),
None => match self.inner.parent {
Some(ref parent) => parent.get_with_source(field),
None => None,
},
}
}
get_fn!(
"Returns the `bool` found at `field`. \
Returns an error if the field was not found \
or if the `Value` at `field` is not `Bool`.",
get_bool,
bool
);
get_fn!(
"Returns the `BigInt` found at `field`. \
Returns an error if the field was not found \
or if the `Value` at `field` is not `Int`.",
get_int,
BigInt
);
get_fn!(
"Returns the `BigRational` found at `field`. \
Returns an error if the field was not found \
or if the `Value` at `field` is not `Frac`.",
get_frac,
BigRational
);
get_fn!(
"Returns the `char` found at `field`. \
Returns an error if the field was not found \
or if the `Value` at `field` is not `Char`.",
get_char,
char
);
get_fn!(
"Returns the `String` found at `field`. \
Returns an error if the field was not found \
or if the `Value` at `field` is not `Str`.",
get_str,
String
);
get_fn!(
"Returns the `Arr` found at `field`. \
Returns an error if the field was not found \
or if the `Value` at `field` is not `Arr`.",
get_arr,
Arr
);
get_fn!(
"Returns the `Tup` found at `field`. \
Returns an error if the field was not found \
or if the `Value` at `field` is not `Tup`.",
get_tup,
Tup
);
get_fn!(
"Returns the `Obj` found at `field`. \
Returns an error if the field was not found \
or if the `Value` at `field` is not `Obj`.",
get_obj,
Obj
);
pub fn has_parent(&self) -> bool {
self.inner.parent.is_some()
}
pub fn get_parent(&self) -> Option<Obj> {
match self.inner.parent {
Some(ref parent) => Some(parent.clone()),
None => None,
}
}
pub fn is_valid_field(field: &str) -> bool {
let mut first = true;
for ch in field.chars() {
if first {
if !Self::is_valid_field_char(ch, true) {
return false;
}
first = false;
} else if !Self::is_valid_field_char(ch, false) {
return false;
}
}
true
}
pub fn is_valid_field_char(ch: char, first: bool) -> bool {
match ch {
ch if ch.is_alphabetic() => true,
ch if is_digit(ch) => !first,
'_' => true,
'^' => first,
_ => false,
}
}
pub fn keys(&self) -> Keys<String, Value> {
self.map_ref().keys()
}
pub fn values(&self) -> Values<String, Value> {
self.map_ref().values()
}
pub fn iter(&self) -> Iter<String, Value> {
self.map_ref().iter()
}
}
impl Default for Obj {
fn default() -> Self {
Self::from_map_unchecked(map! {})
}
}
impl fmt::Display for Obj {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", self.format(true, INDENT_STEP))
}
}
impl FromStr for Obj {
type Err = OverError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
Ok(parse::load_from_str(s)?)
}
}
impl PartialEq for Obj {
fn eq(&self, other: &Self) -> bool {
let inner = &self.inner;
let other_inner = &other.inner;
if inner.parent.is_some() && other_inner.parent.is_some() {
let parent = self.get_parent().unwrap();
let other_parent = other.get_parent().unwrap();
if parent != other_parent {
return false;
}
} else if !(inner.parent.is_none() && other_inner.parent.is_none()) {
return false;
}
inner.map == other_inner.map
}
}