use seq_macro::seq;
use crate::{
Ruby,
r_array::RArray,
r_hash::RHash,
value::{ReprValue, Value},
};
impl Ruby {
#[allow(clippy::wrong_self_convention)]
#[inline]
pub fn into_value<T>(&self, val: T) -> Value
where
T: IntoValue,
{
val.into_value_with(self)
}
}
pub trait IntoValue: Sized {
#[deprecated(note = "please use `IntoValue::into_value_with` instead")]
#[cfg(feature = "old-api")]
#[cfg_attr(docsrs, doc(cfg(feature = "old-api")))]
#[inline]
fn into_value(self) -> Value {
self.into_value_with(&get_ruby!())
}
#[deprecated(note = "please use `IntoValue::into_value_with(&Ruby::get_unchecked())` instead")]
#[inline]
unsafe fn into_value_unchecked(self) -> Value {
unsafe { self.into_value_with(&Ruby::get_unchecked()) }
}
fn into_value_with(self, handle: &Ruby) -> Value;
}
pub unsafe trait IntoValueFromNative: IntoValue {}
pub trait ArgList {
type Value: ReprValue;
type Output: AsRef<[Self::Value]>;
fn into_arg_list_with(self, handle: &Ruby) -> Self::Output;
fn contains_kw_args(&self) -> bool;
}
pub(crate) fn kw_splat(args: &impl RArrayArgList) -> u32 {
if args.contains_kw_args() {
rb_sys::RB_PASS_KEYWORDS
} else {
rb_sys::RB_NO_KEYWORDS
}
}
#[repr(transparent)]
pub struct KwArgs(pub RHash);
#[macro_export]
macro_rules! kwargs {
($ruby:expr_2021, $($k:literal => $v:expr_2021),+) => {{
use $crate::IntoValue;
let h = $ruby.hash_new();
$(
h.aset(
$ruby.to_symbol($k),
$v.into_value_with($ruby),
).unwrap();
)+
$crate::KwArgs(h)
}};
($($k:literal => $v:expr_2021),+) => {{
$crate::kwargs!(&$crate::Ruby::get().unwrap(), $($k => $v),+)
}};
}
impl<'a, T> ArgList for &'a [T]
where
T: ReprValue,
{
type Value = T;
type Output = &'a [Self::Value];
fn into_arg_list_with(self, _: &Ruby) -> Self::Output {
self
}
fn contains_kw_args(&self) -> bool {
false
}
}
macro_rules! impl_arg_list {
($n:literal) => {
seq!(N in 0..$n {
impl<#(T~N,)*> ArgList for (#(T~N,)*)
where
#(T~N: IntoValue,)*
{
type Value = Value;
type Output = [Self::Value; $n];
#[allow(unused_variables)]
fn into_arg_list_with(self, handle: &Ruby) -> Self::Output {
[#(handle.into_value(self.N),)*]
}
fn contains_kw_args(&self) -> bool {
false
}
}
});
}
}
seq!(N in 0..=12 {
impl_arg_list!(N);
});
macro_rules! impl_arg_list_kw {
($n:literal) => {
seq!(N in 0..$n {
impl<#(T~N,)*> ArgList for (#(T~N,)* KwArgs,)
where
#(T~N: IntoValue,)*
{
type Value = Value;
type Output = [Self::Value; { $n + 1 }];
#[allow(unused_variables)]
fn into_arg_list_with(self, handle: &Ruby) -> Self::Output {
[#(handle.into_value(self.N),)* handle.into_value(self.$n.0)]
}
fn contains_kw_args(&self) -> bool {
true
}
}
});
}
}
seq!(N in 0..=12 {
impl_arg_list_kw!(N);
});
impl<T, const N: usize> ArgList for [T; N]
where
T: ReprValue,
{
type Value = T;
type Output = [Self::Value; N];
fn into_arg_list_with(self, _: &Ruby) -> Self::Output {
self
}
fn contains_kw_args(&self) -> bool {
false
}
}
pub trait RArrayArgList {
fn into_array_arg_list_with(self, handle: &Ruby) -> RArray;
fn contains_kw_args(&self) -> bool;
}
impl RArrayArgList for RArray {
fn into_array_arg_list_with(self, _: &Ruby) -> RArray {
self
}
fn contains_kw_args(&self) -> bool {
false
}
}
impl<T> RArrayArgList for T
where
T: ArgList,
{
fn into_array_arg_list_with(self, handle: &Ruby) -> RArray {
handle.ary_new_from_values(self.into_arg_list_with(handle).as_ref())
}
fn contains_kw_args(&self) -> bool {
<Self as ArgList>::contains_kw_args(self)
}
}