use std::borrow::Cow;
use std::cell::RefCell;
use std::collections::HashSet;
use std::ops::{Deref, DerefMut};
use std::sync::Arc;
use crate::error::{Error, ErrorKind};
use crate::value::{
DynObject, ObjectExt, ObjectRepr, Packed, SmallStr, StringType, Value, ValueKind, ValueMap,
ValueRepr,
};
use crate::vm::State;
use super::{Enumerator, Object};
pub trait FunctionResult {
#[doc(hidden)]
fn into_result(self) -> Result<Value, Error>;
}
impl<I: Into<Value>> FunctionResult for Result<I, Error> {
fn into_result(self) -> Result<Value, Error> {
self.map(Into::into)
}
}
impl<I: Into<Value>> FunctionResult for I {
fn into_result(self) -> Result<Value, Error> {
Ok(self.into())
}
}
pub trait FunctionArgs<'a> {
type Output;
#[doc(hidden)]
fn from_values(state: Option<&'a State>, values: &'a [Value]) -> Result<Self::Output, Error>;
#[doc(hidden)]
fn from_values_mut(_state: Option<&State>, values: &'a [Value]) -> Result<Self::Output, Error> {
Self::from_values(None, values)
}
}
#[inline(always)]
pub fn from_args<'a, Args>(values: &'a [Value]) -> Result<Args, Error>
where
Args: FunctionArgs<'a, Output = Args>,
{
Args::from_values(None, values)
}
pub trait ArgType<'a> {
type Output;
#[doc(hidden)]
fn from_value(value: Option<&'a Value>) -> Result<Self::Output, Error>;
#[doc(hidden)]
fn from_value_owned(_value: Value) -> Result<Self::Output, Error> {
Err(Error::new(
ErrorKind::InvalidOperation,
"type conversion is not legal in this situation (implicit borrow)",
))
}
#[doc(hidden)]
fn from_state_and_value_owned(
_state: Option<&'a State>,
value: Value,
) -> Result<Self::Output, Error> {
Self::from_value_owned(value)
}
#[doc(hidden)]
fn from_state_and_value(
_state: Option<&'a State>,
value: Option<&'a Value>,
) -> Result<(Self::Output, usize), Error> {
Ok((ok!(Self::from_value(value)), 1))
}
#[doc(hidden)]
#[inline(always)]
fn from_state_and_values(
state: Option<&'a State>,
values: &'a [Value],
offset: usize,
) -> Result<(Self::Output, usize), Error> {
Self::from_state_and_value(state, values.get(offset))
}
#[doc(hidden)]
fn from_state_and_value_owned_mut(
_state: Option<&State>,
value: Value,
) -> Result<Self::Output, Error> {
Self::from_value_owned(value)
}
#[doc(hidden)]
fn from_state_and_value_mut(
_state: Option<&State>,
value: Option<&'a Value>,
) -> Result<(Self::Output, usize), Error> {
Ok((ok!(Self::from_value(value)), 1))
}
#[doc(hidden)]
#[inline(always)]
fn from_state_and_values_mut(
state: Option<&State>,
values: &'a [Value],
offset: usize,
) -> Result<(Self::Output, usize), Error> {
Self::from_state_and_value_mut(state, values.get(offset))
}
#[doc(hidden)]
#[inline(always)]
fn is_trailing() -> bool {
false
}
}
macro_rules! convert_function_args {
($state:expr, $values:expr, $convert:ident, ($($name:ident,)*), $rest_name:ident) => {{
#![allow(non_snake_case)]
let mut values = $values;
$(let $name;)*
let mut $rest_name = None;
let mut idx = 0;
let rest_first = $rest_name::is_trailing() && !values.is_empty();
if rest_first {
let (val, offset) = ok!($rest_name::$convert(
$state,
values,
values.len() - 1,
));
$rest_name = Some(val);
values = &values[..values.len() - offset];
}
$(
let (val, offset) = ok!($name::$convert($state, values, idx));
$name = val;
idx += offset;
)*
if !rest_first {
let (val, offset) = ok!($rest_name::$convert($state, values, idx));
$rest_name = Some(val);
idx += offset;
}
if values.get(idx).is_some() {
Err(Error::from(ErrorKind::TooManyArguments))
} else {
Ok(($($name,)* $rest_name.expect("trailing argument was not converted"),))
}
}};
}
macro_rules! tuple_impls {
( $( $name:ident )* * $rest_name:ident ) => {
impl<'a, $($name,)* $rest_name> FunctionArgs<'a> for ($($name,)* $rest_name,)
where $($name: ArgType<'a>,)* $rest_name: ArgType<'a>
{
type Output = ($($name::Output,)* $rest_name::Output ,);
fn from_values(state: Option<&'a State>, values: &'a [Value]) -> Result<Self::Output, Error> {
convert_function_args!(
state,
values,
from_state_and_values,
($($name,)*),
$rest_name
)
}
fn from_values_mut(state: Option<&State>, values: &'a [Value]) -> Result<Self::Output, Error> {
convert_function_args!(
state,
values,
from_state_and_values_mut,
($($name,)*),
$rest_name
)
}
}
};
}
impl<'a> FunctionArgs<'a> for () {
type Output = ();
fn from_values(_state: Option<&'a State>, values: &'a [Value]) -> Result<Self::Output, Error> {
if values.is_empty() {
Ok(())
} else {
Err(Error::from(ErrorKind::TooManyArguments))
}
}
}
tuple_impls! { *A }
tuple_impls! { A *B }
tuple_impls! { A B *C }
tuple_impls! { A B C *D }
tuple_impls! { A B C D *E }
impl From<ValueRepr> for Value {
#[inline(always)]
fn from(val: ValueRepr) -> Value {
Value(val)
}
}
impl From<&Value> for Value {
#[inline(always)]
fn from(value: &Value) -> Value {
value.clone()
}
}
impl<'a> From<&'a [u8]> for Value {
#[inline(always)]
fn from(val: &'a [u8]) -> Self {
ValueRepr::Bytes(Arc::new(val.into())).into()
}
}
impl<'a> From<&'a str> for Value {
#[inline(always)]
fn from(val: &'a str) -> Self {
SmallStr::try_new(val)
.map(|small_str| Value(ValueRepr::SmallStr(small_str)))
.unwrap_or_else(|| Value(ValueRepr::String(val.into(), StringType::Normal)))
}
}
impl<'a> From<&'a String> for Value {
#[inline(always)]
fn from(val: &'a String) -> Self {
Value::from(val.as_str())
}
}
impl From<String> for Value {
#[inline(always)]
fn from(val: String) -> Self {
Value::from(val.as_str())
}
}
impl<'a> From<Cow<'a, str>> for Value {
#[inline(always)]
fn from(val: Cow<'a, str>) -> Self {
match val {
Cow::Borrowed(x) => x.into(),
Cow::Owned(x) => x.into(),
}
}
}
impl From<&Cow<'_, str>> for Value {
#[inline(always)]
fn from(val: &Cow<'_, str>) -> Self {
Value::from(val.as_ref())
}
}
impl From<Arc<str>> for Value {
fn from(value: Arc<str>) -> Self {
Value(ValueRepr::String(value, StringType::Normal))
}
}
impl From<&Arc<str>> for Value {
fn from(value: &Arc<str>) -> Self {
Value::from(value.clone())
}
}
impl From<()> for Value {
#[inline(always)]
fn from(_: ()) -> Self {
ValueRepr::None.into()
}
}
impl From<&()> for Value {
#[inline(always)]
fn from(_: &()) -> Self {
ValueRepr::None.into()
}
}
impl From<&[Value]> for Value {
fn from(value: &[Value]) -> Self {
value.iter().cloned().collect()
}
}
impl<V: Into<Value>> FromIterator<V> for Value {
fn from_iter<T: IntoIterator<Item = V>>(iter: T) -> Self {
Value::from_object(iter.into_iter().map(Into::into).collect::<Vec<Value>>())
}
}
macro_rules! value_from {
($src:ty, $dst:ident) => {
impl From<$src> for Value {
#[inline(always)]
fn from(val: $src) -> Self {
ValueRepr::$dst(val as _).into()
}
}
};
}
macro_rules! value_from_copy_ref {
($($src:ty),*) => {
$(
impl From<&$src> for Value {
#[inline(always)]
fn from(val: &$src) -> Self {
Value::from(*val)
}
}
)*
};
}
impl From<i128> for Value {
#[inline(always)]
fn from(val: i128) -> Self {
ValueRepr::I128(Packed(val)).into()
}
}
impl From<u128> for Value {
#[inline(always)]
fn from(val: u128) -> Self {
ValueRepr::U128(Packed(val)).into()
}
}
impl From<char> for Value {
#[inline(always)]
fn from(val: char) -> Self {
let mut buf = [0u8; 4];
ValueRepr::SmallStr(SmallStr::try_new(val.encode_utf8(&mut buf)).unwrap()).into()
}
}
value_from!(bool, Bool);
value_from!(u8, U64);
value_from!(u16, U64);
value_from!(u32, U64);
value_from!(u64, U64);
value_from!(i8, I64);
value_from!(i16, I64);
value_from!(i32, I64);
value_from!(i64, I64);
value_from!(f32, F64);
value_from!(f64, F64);
value_from!(Arc<Vec<u8>>, Bytes);
value_from!(DynObject, Object);
value_from_copy_ref!(
bool, char, usize, isize, u8, u16, u32, u64, u128, i8, i16, i32, i64, i128, f32, f64
);
impl From<&Arc<Vec<u8>>> for Value {
fn from(value: &Arc<Vec<u8>>) -> Self {
Value::from(value.clone())
}
}
impl From<&DynObject> for Value {
fn from(value: &DynObject) -> Self {
Value::from(value.clone())
}
}
fn unsupported_conversion(kind: ValueKind, target: &str) -> Error {
Error::new(
ErrorKind::InvalidOperation,
format!("cannot convert {kind} to {target}"),
)
}
macro_rules! primitive_try_from {
($ty:ident, {
$($pat:pat $(if $if_expr:expr)? => $expr:expr,)*
}) => {
impl TryFrom<Value> for $ty {
type Error = Error;
fn try_from(value: Value) -> Result<Self, Self::Error> {
match value.0 {
$($pat $(if $if_expr)? => TryFrom::try_from($expr).ok(),)*
_ => None
}.ok_or_else(|| unsupported_conversion(value.kind(), stringify!($ty)))
}
}
impl<'a> ArgType<'a> for $ty {
type Output = Self;
fn from_value(value: Option<&Value>) -> Result<Self, Error> {
match value {
Some(value) => TryFrom::try_from(value.clone()),
None => Err(Error::from(ErrorKind::MissingArgument))
}
}
fn from_value_owned(value: Value) -> Result<Self, Error> {
TryFrom::try_from(value)
}
}
}
}
macro_rules! primitive_int_try_from {
($ty:ident) => {
primitive_try_from!($ty, {
ValueRepr::Bool(val) => val as usize,
ValueRepr::I64(val) => val,
ValueRepr::U64(val) => val,
ValueRepr::F64(val) if (val as i64 as f64 == val) => val as i64,
ValueRepr::I128(val) => val.0,
ValueRepr::U128(val) => val.0,
});
}
}
primitive_int_try_from!(u8);
primitive_int_try_from!(u16);
primitive_int_try_from!(u32);
primitive_int_try_from!(u64);
primitive_int_try_from!(u128);
primitive_int_try_from!(i8);
primitive_int_try_from!(i16);
primitive_int_try_from!(i32);
primitive_int_try_from!(i64);
primitive_int_try_from!(i128);
primitive_int_try_from!(usize);
primitive_int_try_from!(isize);
primitive_try_from!(bool, {
ValueRepr::Bool(val) => val,
});
primitive_try_from!(char, {
ValueRepr::String(ref val, _) => {
let mut char_iter = val.chars();
ok!(char_iter.next().filter(|_| char_iter.next().is_none()).ok_or_else(|| {
unsupported_conversion(ValueKind::String, "non single character string")
}))
},
ValueRepr::SmallStr(ref val) => {
let mut char_iter = val.as_str().chars();
ok!(char_iter.next().filter(|_| char_iter.next().is_none()).ok_or_else(|| {
unsupported_conversion(ValueKind::String, "non single character string")
}))
},
});
primitive_try_from!(f32, {
ValueRepr::U64(val) => val as f32,
ValueRepr::I64(val) => val as f32,
ValueRepr::U128(val) => val.0 as f32,
ValueRepr::I128(val) => val.0 as f32,
ValueRepr::F64(val) => val as f32,
});
primitive_try_from!(f64, {
ValueRepr::U64(val) => val as f64,
ValueRepr::I64(val) => val as f64,
ValueRepr::U128(val) => val.0 as f64,
ValueRepr::I128(val) => val.0 as f64,
ValueRepr::F64(val) => val,
});
impl<'a> ArgType<'a> for &str {
type Output = &'a str;
fn from_value(value: Option<&'a Value>) -> Result<Self::Output, Error> {
match value {
Some(value) => value
.as_str()
.ok_or_else(|| Error::new(ErrorKind::InvalidOperation, "value is not a string")),
None => Err(Error::from(ErrorKind::MissingArgument)),
}
}
}
impl TryFrom<Value> for Arc<str> {
type Error = Error;
fn try_from(value: Value) -> Result<Self, Self::Error> {
match value.0 {
ValueRepr::String(x, _) => Ok(x),
ValueRepr::SmallStr(x) => Ok(Arc::from(x.as_str())),
ValueRepr::Bytes(ref x) => Ok(Arc::from(String::from_utf8_lossy(x))),
_ => Err(Error::new(
ErrorKind::InvalidOperation,
"value is not a string",
)),
}
}
}
impl<'a> ArgType<'a> for Arc<str> {
type Output = Arc<str>;
fn from_value(value: Option<&'a Value>) -> Result<Self::Output, Error> {
match value {
Some(value) => TryFrom::try_from(value.clone()),
None => Err(Error::from(ErrorKind::MissingArgument)),
}
}
}
impl<'a> ArgType<'a> for &[u8] {
type Output = &'a [u8];
fn from_value(value: Option<&'a Value>) -> Result<Self::Output, Error> {
match value {
Some(value) => value
.as_bytes()
.ok_or_else(|| Error::new(ErrorKind::InvalidOperation, "value is not in bytes")),
None => Err(Error::from(ErrorKind::MissingArgument)),
}
}
}
impl<'a, T: ArgType<'a>> ArgType<'a> for Option<T> {
type Output = Option<T::Output>;
fn from_value(value: Option<&'a Value>) -> Result<Self::Output, Error> {
match value {
Some(value) => {
if value.is_undefined() || value.is_none() {
Ok(None)
} else {
T::from_value(Some(value)).map(Some)
}
}
None => Ok(None),
}
}
fn from_value_owned(value: Value) -> Result<Self::Output, Error> {
if value.is_undefined() || value.is_none() {
Ok(None)
} else {
T::from_value_owned(value).map(Some)
}
}
}
fn value_to_string_cow(value: &Value) -> Result<Cow<'_, str>, Error> {
Ok(match value.0 {
ValueRepr::String(ref s, _) => Cow::Borrowed(s as &str),
ValueRepr::SmallStr(ref s) => Cow::Borrowed(s.as_str()),
ValueRepr::U64(v) => Cow::Owned(v.to_string()),
ValueRepr::I64(v) => Cow::Owned(v.to_string()),
ValueRepr::Bool(v) => Cow::Borrowed(if v { "True" } else { "False" }),
_ => {
if value.is_kwargs() {
return Err(Error::new(
ErrorKind::InvalidOperation,
"cannot convert kwargs to string",
));
}
Cow::Owned(value.to_string())
}
})
}
#[derive(Debug)]
pub struct StringInput<'a> {
value: Cow<'a, str>,
safe: bool,
}
impl<'a> StringInput<'a> {
pub fn new(state: &State, value: &'a Value) -> Result<Self, Error> {
ok!(state.undefined_behavior().assert_value_not_undefined(value));
Self::from_value(value)
}
fn from_value(value: &'a Value) -> Result<Self, Error> {
Ok(StringInput {
value: ok!(value_to_string_cow(value)),
safe: value.is_safe(),
})
}
pub fn as_str(&self) -> &str {
&self.value
}
pub fn is_safe(&self) -> bool {
self.safe
}
pub fn format(&self, state: &mut State) -> Result<Cow<'_, str>, Error> {
if self.safe {
Ok(Cow::Borrowed(self.as_str()))
} else {
Ok(Cow::Owned(
crate::filters::escape(state, &Value::from(self.as_str()))?
.as_str()
.unwrap()
.to_string(),
))
}
}
pub fn preserve_safety(&self, value: String) -> Value {
if self.safe {
Value::from_safe_string(value)
} else {
Value::from(value)
}
}
}
impl<'a> ArgType<'a> for StringInput<'_> {
type Output = StringInput<'a>;
fn from_value(value: Option<&'a Value>) -> Result<Self::Output, Error> {
match value {
Some(value) => StringInput::from_value(value),
None => Err(Error::from(ErrorKind::MissingArgument)),
}
}
fn from_state_and_value(
state: Option<&'a State>,
value: Option<&'a Value>,
) -> Result<(Self::Output, usize), Error> {
Self::from_state_and_value_mut(state, value)
}
fn from_state_and_value_mut(
state: Option<&State>,
value: Option<&'a Value>,
) -> Result<(Self::Output, usize), Error> {
let value = value.ok_or_else(|| Error::from(ErrorKind::MissingArgument))?;
if let Some(state) = state {
ok!(state.undefined_behavior().assert_value_not_undefined(value));
}
Ok((ok!(StringInput::from_value(value)), 1))
}
}
impl<'a> ArgType<'a> for Cow<'_, str> {
type Output = Cow<'a, str>;
#[inline(always)]
fn from_value(value: Option<&'a Value>) -> Result<Cow<'a, str>, Error> {
match value {
Some(value) => value_to_string_cow(value),
None => Err(Error::from(ErrorKind::MissingArgument)),
}
}
fn from_state_and_value(
state: Option<&'a State>,
value: Option<&'a Value>,
) -> Result<(Self::Output, usize), Error> {
Self::from_state_and_value_mut(state, value)
}
fn from_state_and_value_mut(
state: Option<&State>,
value: Option<&'a Value>,
) -> Result<(Self::Output, usize), Error> {
if let (Some(state), Some(value)) = (state, value) {
ok!(state.undefined_behavior().assert_value_not_undefined(value));
}
Ok((ok!(Self::from_value(value)), 1))
}
}
impl<'a> ArgType<'a> for &Value {
type Output = &'a Value;
#[inline(always)]
fn from_value(value: Option<&'a Value>) -> Result<&'a Value, Error> {
match value {
Some(value) if !value.is_kwargs() => Ok(value),
Some(_) => Err(unexpected_kwargs()),
None => Err(Error::from(ErrorKind::MissingArgument)),
}
}
}
impl<'a> ArgType<'a> for &[Value] {
type Output = &'a [Value];
#[inline(always)]
fn from_value(value: Option<&'a Value>) -> Result<&'a [Value], Error> {
match value {
Some(value) if !value.is_kwargs() => Ok(std::slice::from_ref(value)),
Some(_) => Err(unexpected_kwargs()),
None => Err(Error::from(ErrorKind::MissingArgument)),
}
}
fn from_state_and_values(
_state: Option<&'a State>,
values: &'a [Value],
offset: usize,
) -> Result<(&'a [Value], usize), Error> {
Self::from_state_and_values_mut(None, values, offset)
}
fn from_state_and_values_mut(
_state: Option<&State>,
values: &'a [Value],
offset: usize,
) -> Result<(&'a [Value], usize), Error> {
let args = values.get(offset..).unwrap_or_default();
if args.iter().any(Value::is_kwargs) {
return Err(unexpected_kwargs());
}
Ok((args, args.len()))
}
}
impl<'a, T: Object + 'static> ArgType<'a> for &T {
type Output = &'a T;
#[inline(always)]
fn from_value(value: Option<&'a Value>) -> Result<Self::Output, Error> {
match value {
Some(value) => value
.downcast_object_ref()
.ok_or_else(|| Error::new(ErrorKind::InvalidOperation, "expected object")),
None => Err(Error::from(ErrorKind::MissingArgument)),
}
}
}
impl<'a, T: Object + 'static> ArgType<'a> for Arc<T> {
type Output = Arc<T>;
#[inline(always)]
fn from_value(value: Option<&'a Value>) -> Result<Self::Output, Error> {
match value {
Some(value) => value
.downcast_object()
.ok_or_else(|| Error::new(ErrorKind::InvalidOperation, "expected object")),
None => Err(Error::from(ErrorKind::MissingArgument)),
}
}
}
#[derive(Debug)]
pub struct Rest<T>(pub Vec<T>);
impl<T> Deref for Rest<T> {
type Target = Vec<T>;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl<T> DerefMut for Rest<T> {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.0
}
}
impl Rest<ValueOrKwargs> {
pub fn into_values(self) -> Vec<Value> {
self.0.into_iter().map(ValueOrKwargs::into_value).collect()
}
}
impl<'a, T: ArgType<'a, Output = T>> ArgType<'a> for Rest<T> {
type Output = Self;
fn from_value(value: Option<&'a Value>) -> Result<Self, Error> {
Ok(Rest(ok!(value
.iter()
.map(|v| T::from_value(Some(v)))
.collect::<Result<_, _>>())))
}
fn from_state_and_values(
state: Option<&'a State>,
values: &'a [Value],
offset: usize,
) -> Result<(Self, usize), Error> {
let args = values.get(offset..).unwrap_or_default();
Ok((
Rest(ok!(args
.iter()
.map(|v| T::from_state_and_value(state, Some(v)).map(|x| x.0))
.collect::<Result<_, _>>())),
args.len(),
))
}
fn from_state_and_values_mut(
state: Option<&State>,
values: &'a [Value],
offset: usize,
) -> Result<(Self, usize), Error> {
let args = values.get(offset..).unwrap_or_default();
Ok((
Rest(ok!(args
.iter()
.map(|v| T::from_state_and_value_mut(state, Some(v)).map(|x| x.0))
.collect::<Result<_, _>>())),
args.len(),
))
}
}
#[derive(Debug, Clone)]
pub struct Kwargs {
pub(crate) values: Arc<KwargsValues>,
used: RefCell<HashSet<String>>,
}
#[repr(transparent)]
#[derive(Default, Debug)]
pub(crate) struct KwargsValues(ValueMap);
impl Deref for KwargsValues {
type Target = ValueMap;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl Object for KwargsValues {
fn get_value(self: &Arc<Self>, key: &Value) -> Option<Value> {
self.0.get(key).cloned()
}
fn enumerate(self: &Arc<Self>) -> Enumerator {
self.mapped_enumerator(|this| Box::new(this.0.keys().cloned()))
}
fn enumerator_len(self: &Arc<Self>) -> Option<usize> {
Some(self.0.len())
}
}
impl<'a> ArgType<'a> for Kwargs {
type Output = Self;
fn from_value(value: Option<&'a Value>) -> Result<Self, Error> {
match value {
Some(value) => {
Kwargs::extract(value).ok_or_else(|| Error::from(ErrorKind::MissingArgument))
}
None => Ok(Kwargs::new(Default::default())),
}
}
fn from_state_and_values(
_state: Option<&'a State>,
values: &'a [Value],
offset: usize,
) -> Result<(Self, usize), Error> {
Self::from_state_and_values_mut(None, values, offset)
}
fn from_state_and_values_mut(
_state: Option<&State>,
values: &'a [Value],
offset: usize,
) -> Result<(Self, usize), Error> {
let args = values
.get(offset)
.and_then(Kwargs::extract)
.map(|kwargs| (kwargs, 1))
.unwrap_or_else(|| (Kwargs::new(Default::default()), 0));
Ok(args)
}
fn is_trailing() -> bool {
true
}
}
impl Kwargs {
fn new(map: Arc<KwargsValues>) -> Kwargs {
Kwargs {
values: map,
used: RefCell::new(HashSet::new()),
}
}
pub(crate) fn is_kwargs(value: &Value) -> bool {
value
.as_object()
.and_then(|x| x.downcast_ref::<KwargsValues>())
.is_some()
}
pub(crate) fn extract(value: &Value) -> Option<Kwargs> {
value
.as_object()
.and_then(|x| x.downcast::<KwargsValues>())
.map(Kwargs::new)
}
pub(crate) fn wrap(map: ValueMap) -> Value {
Value::from_object(KwargsValues(map))
}
pub fn peek<'a, T>(&'a self, key: &'a str) -> Result<T, Error>
where
T: ArgType<'a, Output = T>,
{
T::from_value(self.values.get(&Value::from(key))).map_err(|mut err| {
if err.kind() == ErrorKind::MissingArgument && err.detail().is_none() {
err.set_detail(format!("missing keyword argument '{key}'"));
}
err
})
}
pub fn get<'a, T>(&'a self, key: &'a str) -> Result<T, Error>
where
T: ArgType<'a, Output = T>,
{
let rv = ok!(self.peek::<T>(key));
self.used.borrow_mut().insert(key.to_string());
Ok(rv)
}
pub fn has(&self, key: &str) -> bool {
self.values.contains_key(&Value::from(key))
}
pub fn args(&self) -> impl Iterator<Item = &str> {
self.values.iter().filter_map(|x| x.0.as_str())
}
pub fn assert_all_used(&self) -> Result<(), Error> {
let used = self.used.borrow();
for key in self.values.keys() {
if let Some(key) = key.as_str() {
if !used.contains(key) {
return Err(Error::new(
ErrorKind::TooManyArguments,
format!("unknown keyword argument '{key}'"),
));
}
} else {
return Err(Error::new(
ErrorKind::InvalidOperation,
"non string keys passed to kwargs",
));
}
}
Ok(())
}
}
impl FromIterator<(String, Value)> for Kwargs {
fn from_iter<T>(iter: T) -> Self
where
T: IntoIterator<Item = (String, Value)>,
{
Kwargs::new(Arc::new(KwargsValues(
iter.into_iter().map(|(k, v)| (Value::from(k), v)).collect(),
)))
}
}
impl<'a> FromIterator<(&'a str, Value)> for Kwargs {
fn from_iter<T>(iter: T) -> Self
where
T: IntoIterator<Item = (&'a str, Value)>,
{
Kwargs::new(Arc::new(KwargsValues(
iter.into_iter().map(|(k, v)| (Value::from(k), v)).collect(),
)))
}
}
impl From<Kwargs> for Value {
fn from(value: Kwargs) -> Self {
Value::from_dyn_object(value.values)
}
}
impl TryFrom<Value> for Kwargs {
type Error = Error;
fn try_from(value: Value) -> Result<Self, Self::Error> {
match value.0 {
ValueRepr::Undefined(_) => Ok(Kwargs::new(Default::default())),
ValueRepr::Object(_) => {
Kwargs::extract(&value).ok_or_else(|| Error::from(ErrorKind::InvalidOperation))
}
_ => Err(Error::from(ErrorKind::InvalidOperation)),
}
}
}
fn unexpected_kwargs() -> Error {
Error::new(ErrorKind::TooManyArguments, "unexpected keyword arguments")
}
#[derive(Clone, Debug)]
pub struct ValueOrKwargs(Value);
impl ValueOrKwargs {
pub fn into_value(self) -> Value {
self.0
}
}
impl Deref for ValueOrKwargs {
type Target = Value;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl From<Value> for ValueOrKwargs {
fn from(value: Value) -> Self {
ValueOrKwargs(value)
}
}
impl From<ValueOrKwargs> for Value {
fn from(value: ValueOrKwargs) -> Self {
value.0
}
}
impl<'a> ArgType<'a> for ValueOrKwargs {
type Output = Self;
fn from_value(value: Option<&'a Value>) -> Result<Self, Error> {
match value {
Some(value) => Ok(ValueOrKwargs(value.clone())),
None => Err(Error::from(ErrorKind::MissingArgument)),
}
}
fn from_value_owned(value: Value) -> Result<Self, Error> {
Ok(ValueOrKwargs(value))
}
}
impl<'a> ArgType<'a> for Value {
type Output = Self;
fn from_value(value: Option<&'a Value>) -> Result<Self, Error> {
match value {
Some(value) if !value.is_kwargs() => Ok(value.clone()),
Some(_) => Err(unexpected_kwargs()),
None => Err(Error::from(ErrorKind::MissingArgument)),
}
}
fn from_value_owned(value: Value) -> Result<Self, Error> {
if value.is_kwargs() {
Err(unexpected_kwargs())
} else {
Ok(value)
}
}
}
impl<'a> ArgType<'a> for String {
type Output = Self;
fn from_value(value: Option<&'a Value>) -> Result<Self, Error> {
match value {
Some(value) => {
if value.is_kwargs() {
return Err(Error::new(
ErrorKind::InvalidOperation,
"cannot convert kwargs to string",
));
}
Ok(value.to_string())
}
None => Err(Error::from(ErrorKind::MissingArgument)),
}
}
fn from_state_and_value(
state: Option<&'a State>,
value: Option<&'a Value>,
) -> Result<(Self::Output, usize), Error> {
Self::from_state_and_value_mut(state, value)
}
fn from_state_and_value_mut(
state: Option<&State>,
value: Option<&'a Value>,
) -> Result<(Self::Output, usize), Error> {
if let (Some(state), Some(value)) = (state, value) {
ok!(state.undefined_behavior().assert_value_not_undefined(value));
}
Ok((ok!(Self::from_value(value)), 1))
}
fn from_state_and_value_owned(
state: Option<&'a State>,
value: Value,
) -> Result<Self::Output, Error> {
Self::from_state_and_value_owned_mut(state, value)
}
fn from_state_and_value_owned_mut(
state: Option<&State>,
value: Value,
) -> Result<Self::Output, Error> {
if let Some(state) = state {
ok!(state
.undefined_behavior()
.assert_value_not_undefined(&value));
}
Self::from_value_owned(value)
}
fn from_value_owned(value: Value) -> Result<Self, Error> {
value_to_string_cow(&value).map(Cow::into_owned)
}
}
fn convert_vec<T>(
value: Option<&Value>,
convert: impl FnMut(Value) -> Result<T, Error>,
) -> Result<Vec<T>, Error> {
let Some(value) = value else {
return Ok(Vec::new());
};
value
.as_object()
.filter(|object| matches!(object.repr(), ObjectRepr::Seq | ObjectRepr::Iterable))
.and_then(|object| object.try_iter())
.ok_or_else(|| Error::new(ErrorKind::InvalidOperation, "not iterable"))?
.map(convert)
.collect()
}
impl<'a, T: ArgType<'a, Output = T>> ArgType<'a> for Vec<T> {
type Output = Vec<T>;
fn from_value(value: Option<&'a Value>) -> Result<Self, Error> {
convert_vec(value, T::from_value_owned)
}
fn from_state_and_value(
state: Option<&'a State>,
value: Option<&'a Value>,
) -> Result<(Self::Output, usize), Error> {
convert_vec(value, |value| T::from_state_and_value_owned(state, value)).map(|rv| (rv, 1))
}
fn from_state_and_value_mut(
state: Option<&State>,
value: Option<&'a Value>,
) -> Result<(Self::Output, usize), Error> {
convert_vec(value, |value| {
T::from_state_and_value_owned_mut(state, value)
})
.map(|rv| (rv, 1))
}
fn from_value_owned(value: Value) -> Result<Self, Error> {
convert_vec(Some(&value), T::from_value_owned)
}
}
impl<'a> ArgType<'a> for DynObject {
type Output = Self;
fn from_value(value: Option<&'a Value>) -> Result<Self, Error> {
value
.ok_or_else(|| Error::from(ErrorKind::MissingArgument))
.and_then(|v| Self::from_value_owned(v.clone()))
}
fn from_value_owned(value: Value) -> Result<Self, Error> {
value
.as_object()
.cloned()
.ok_or_else(|| Error::new(ErrorKind::InvalidOperation, "not an object"))
}
}
impl From<Value> for String {
fn from(val: Value) -> Self {
val.to_string()
}
}
impl From<usize> for Value {
fn from(val: usize) -> Self {
Value::from(val as u64)
}
}
impl From<isize> for Value {
fn from(val: isize) -> Self {
Value::from(val as i64)
}
}
impl<I: Into<Value>> From<Option<I>> for Value {
fn from(value: Option<I>) -> Self {
match value {
Some(value) => value.into(),
None => Value::from(()),
}
}
}
impl<I> From<&Option<I>> for Value
where
I: Clone + Into<Value>,
{
fn from(value: &Option<I>) -> Self {
Value::from(value.clone())
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_as_f64() {
let v = Value::from(42u32);
let f: f64 = v.try_into().unwrap();
assert_eq!(f, 42.0);
let v = Value::from(42.5);
let f: f64 = v.try_into().unwrap();
assert_eq!(f, 42.5);
}
#[test]
fn test_split_kwargs() {
let args = [
Value::from(42),
Value::from(true),
Value::from(Kwargs::from_iter([
("foo", Value::from(1)),
("bar", Value::from(2)),
])),
];
let (args, kwargs) = from_args::<(&[Value], Kwargs)>(&args).unwrap();
assert_eq!(args, &[Value::from(42), Value::from(true)]);
assert_eq!(kwargs.get::<Value>("foo").unwrap(), Value::from(1));
assert_eq!(kwargs.get::<Value>("bar").unwrap(), Value::from(2));
}
#[test]
fn test_value_rejects_kwargs() {
let kwargs = Value::from(Kwargs::from_iter([("foo", Value::from(1))]));
assert_eq!(
from_args::<(Value,)>(std::slice::from_ref(&kwargs))
.unwrap_err()
.kind(),
ErrorKind::TooManyArguments
);
assert_eq!(
from_args::<(Rest<Value>,)>(std::slice::from_ref(&kwargs))
.unwrap_err()
.kind(),
ErrorKind::TooManyArguments
);
let (value,) = from_args::<(ValueOrKwargs,)>(&[kwargs]).unwrap();
assert!(value.is_kwargs());
}
#[test]
fn test_kwargs_fails_string_conversion() {
let kwargs = Kwargs::from_iter([("foo", Value::from(1)), ("bar", Value::from(2))]);
let args = [Value::from(kwargs)];
let result = from_args::<(String,)>(&args);
assert!(result.is_err());
assert_eq!(
result.unwrap_err().to_string(),
"invalid operation: cannot convert kwargs to string"
);
let result = from_args::<(Cow<str>,)>(&args);
assert!(result.is_err());
assert_eq!(
result.unwrap_err().to_string(),
"invalid operation: cannot convert kwargs to string"
);
let result = String::from_value_owned(args[0].clone());
assert!(result.is_err());
}
#[test]
fn test_optional_none() {
let (one,) = from_args::<(Option<i32>,)>(args!(None::<i32>)).unwrap();
assert!(one.is_none());
let (one,) = from_args::<(Option<i32>,)>(args!(Some(Value::UNDEFINED))).unwrap();
assert!(one.is_none());
}
}