use std::borrow::Cow;
use indexmap::IndexMap;
use serde::de::DeserializeOwned;
use crate::{Error, Name, Result, Upload, Value};
pub struct ValueAccessor<'a>(&'a Value);
impl<'a> ValueAccessor<'a> {
#[inline]
pub fn is_null(&self) -> bool {
matches!(self.0, Value::Null)
}
pub fn boolean(&self) -> Result<bool> {
match self.0 {
Value::Boolean(b) => Ok(*b),
_ => Err(Error::new("internal: not a boolean")),
}
}
pub fn enum_name(&self) -> Result<&str> {
match self.0 {
Value::Enum(s) => Ok(s),
Value::String(s) => Ok(s.as_str()),
_ => Err(Error::new("internal: not an enum name")),
}
}
pub fn i64(&self) -> Result<i64> {
if let Value::Number(number) = self.0 {
if let Some(value) = number.as_i64() {
return Ok(value);
}
}
Err(Error::new("internal: not an signed integer"))
}
pub fn u64(&self) -> Result<u64> {
if let Value::Number(number) = self.0 {
if let Some(value) = number.as_u64() {
return Ok(value);
}
}
Err(Error::new("internal: not an unsigned integer"))
}
pub fn f32(&self) -> Result<f32> {
if let Value::Number(number) = self.0 {
if let Some(value) = number.as_f64() {
return Ok(value as f32);
}
}
Err(Error::new("internal: not a float"))
}
pub fn f64(&self) -> Result<f64> {
if let Value::Number(number) = self.0 {
if let Some(value) = number.as_f64() {
return Ok(value);
}
}
Err(Error::new("internal: not a float"))
}
pub fn string(&self) -> Result<&'a str> {
if let Value::String(value) = self.0 {
Ok(value)
} else {
Err(Error::new("internal: not a string"))
}
}
pub fn object(&self) -> Result<ObjectAccessor<'a>> {
if let Value::Object(obj) = self.0 {
Ok(ObjectAccessor(Cow::Borrowed(obj)))
} else {
Err(Error::new("internal: not an object"))
}
}
pub fn list(&self) -> Result<ListAccessor<'a>> {
if let Value::List(list) = self.0 {
Ok(ListAccessor(list))
} else {
Err(Error::new("internal: not a list"))
}
}
pub fn deserialize<T: DeserializeOwned>(&self) -> Result<T> {
T::deserialize(self.0.clone()).map_err(|err| format!("internal: {}", err).into())
}
#[inline]
pub fn as_value(&self) -> &'a Value {
self.0
}
pub fn upload(&self) -> Result<Upload> {
<Upload as crate::InputType>::parse(Some(self.0.clone()))
.map_err(|_| Error::new("internal: not a upload"))
}
}
pub struct ObjectAccessor<'a>(pub(crate) Cow<'a, IndexMap<Name, Value>>);
impl<'a> ObjectAccessor<'a> {
#[inline]
pub fn get(&self, name: &str) -> Option<ValueAccessor<'_>> {
self.0.get(name).map(ValueAccessor)
}
#[inline]
pub fn try_get(&self, name: &str) -> Result<ValueAccessor<'_>> {
self.0
.get(name)
.map(ValueAccessor)
.ok_or_else(|| Error::new(format!("internal: key \"{}\" not found", name)))
}
#[inline]
pub fn iter(&self) -> impl Iterator<Item = (&Name, ValueAccessor<'_>)> + '_ {
self.0
.iter()
.map(|(name, value)| (name, ValueAccessor(value)))
}
#[inline]
pub fn keys(&self) -> impl Iterator<Item = &Name> + '_ {
self.0.keys()
}
#[inline]
pub fn values(&self) -> impl Iterator<Item = ValueAccessor<'_>> + '_ {
self.0.values().map(ValueAccessor)
}
#[inline]
pub fn len(&self) -> usize {
self.0.len()
}
#[must_use]
pub fn is_empty(&self) -> bool {
self.len() == 0
}
#[inline]
pub fn as_index_map(&'a self) -> &'a IndexMap<Name, Value> {
&self.0
}
}
pub struct ListAccessor<'a>(pub(crate) &'a [Value]);
impl<'a> ListAccessor<'a> {
#[inline]
pub fn len(&self) -> usize {
self.0.len()
}
#[inline]
pub fn is_empty(&self) -> bool {
self.0.is_empty()
}
#[inline]
pub fn iter(&self) -> impl Iterator<Item = ValueAccessor<'_>> + '_ {
self.0.iter().map(ValueAccessor)
}
#[inline]
pub fn get(&self, idx: usize) -> Option<ValueAccessor<'_>> {
self.0.get(idx).map(ValueAccessor)
}
#[inline]
pub fn try_get(&self, idx: usize) -> Result<ValueAccessor<'_>> {
self.get(idx)
.ok_or_else(|| Error::new(format!("internal: index \"{}\" not found", idx)))
}
#[inline]
pub fn as_slice(&self, start: usize, end: usize) -> Result<ListAccessor<'a>> {
if start <= end && end <= self.len() {
Ok(ListAccessor(&self.0[start..end]))
} else {
Err(Error::new("internal: invalid slice indices"))
}
}
#[inline]
pub fn as_values_slice(&self) -> &'a [Value] {
self.0
}
}