1use super::{
4 NativeBorrow, SexpError, SexpTypeError, TryFromSexp, charsxp_to_cow, charsxp_to_str,
5 map_strsxp_with, map_vecsxp_batched,
6};
7use crate::{RCow, RNativeType, Root, SEXP, SEXPTYPE, SexpExt, StrVec};
8use std::borrow::Cow;
9
10pub trait TryFromRoot<'a>: Sized {
60 type Error;
62
63 #[doc(hidden)]
65 const NATIVE_BORROW: Option<NativeBorrow> = None;
66
67 fn try_from_root(root: Root<'a>) -> Result<Self, Self::Error>;
69}
70
71impl<'a, T: ?Sized + 'static> TryFromRoot<'a> for &'a T
76where
77 &'static T: TryFromSexp,
78{
79 type Error = <&'static T as TryFromSexp>::Error;
80 const NATIVE_BORROW: Option<NativeBorrow> = <&'static T as TryFromSexp>::NATIVE_BORROW;
81
82 fn try_from_root(root: Root<'a>) -> Result<Self, Self::Error> {
83 unsafe { <&'static T as TryFromSexp>::__mx_try_from_rooted(root) }
86 }
87}
88
89impl<'a, T: ?Sized + 'static> TryFromRoot<'a> for Option<&'a T>
91where
92 Option<&'static T>: TryFromSexp,
93{
94 type Error = <Option<&'static T> as TryFromSexp>::Error;
95 const NATIVE_BORROW: Option<NativeBorrow> = <Option<&'static T> as TryFromSexp>::NATIVE_BORROW;
96
97 fn try_from_root(root: Root<'a>) -> Result<Self, Self::Error> {
98 unsafe { <Option<&'static T> as TryFromSexp>::__mx_try_from_rooted(root) }
100 }
101}
102
103impl<'a> TryFromRoot<'a> for StrVec<'a> {
104 type Error = SexpError;
105
106 fn try_from_root(root: Root<'a>) -> Result<Self, Self::Error> {
107 StrVec::try_from_root(root)
108 }
109}
110
111impl<'a, T: RNativeType> TryFromRoot<'a> for RCow<'a, T> {
112 type Error = SexpTypeError;
113 const NATIVE_BORROW: Option<NativeBorrow> = RCow::<'a, T>::NATIVE_BORROW;
114
115 fn try_from_root(root: Root<'a>) -> Result<Self, Self::Error> {
116 RCow::try_from_root(root)
117 }
118}
119
120impl<'a, T: RNativeType> TryFromRoot<'a> for Cow<'a, [T]> {
121 type Error = SexpTypeError;
122 const NATIVE_BORROW: Option<NativeBorrow> = <&[T] as TryFromRoot<'a>>::NATIVE_BORROW;
123
124 fn try_from_root(root: Root<'a>) -> Result<Self, Self::Error> {
125 <&[T]>::try_from_root(root).map(Cow::Borrowed)
126 }
127}
128
129impl<'a> TryFromRoot<'a> for Cow<'a, str> {
130 type Error = SexpError;
131
132 fn try_from_root(root: Root<'a>) -> Result<Self, Self::Error> {
133 <&str>::try_from_root(root).map(Cow::Borrowed)
134 }
135}
136
137#[doc(hidden)]
143pub trait RootedVecElement<'a>: Sized {
144 const NATIVE_BORROW: Option<NativeBorrow>;
146
147 fn vec_from_root(root: Root<'a>) -> Result<Vec<Self>, SexpError>;
149}
150
151impl<'a, E: RootedVecElement<'a>> TryFromRoot<'a> for Vec<E> {
152 type Error = SexpError;
153 const NATIVE_BORROW: Option<NativeBorrow> = E::NATIVE_BORROW;
154
155 fn try_from_root(root: Root<'a>) -> Result<Self, Self::Error> {
156 E::vec_from_root(root)
157 }
158}
159
160impl<'a, E: RootedVecElement<'a>> TryFromRoot<'a> for Option<Vec<E>> {
162 type Error = SexpError;
163 const NATIVE_BORROW: Option<NativeBorrow> = E::NATIVE_BORROW;
164
165 fn try_from_root(root: Root<'a>) -> Result<Self, Self::Error> {
166 if root.get().type_of() == SEXPTYPE::NILSXP {
167 Ok(None)
168 } else {
169 E::vec_from_root(root).map(Some)
170 }
171 }
172}
173
174macro_rules! character_elements {
177 ($life:lifetime; $($element:ty => |$value:ident| $borrow:expr, $na:expr, $blank:expr;)*) => {$(
178 impl<$life> RootedVecElement<$life> for $element {
179 const NATIVE_BORROW: Option<NativeBorrow> = None;
180
181 fn vec_from_root(root: Root<$life>) -> Result<Vec<Self>, SexpError> {
182 map_strsxp_with(root.get(), |value, _| {
183 if value == SEXP::na_string() {
184 Ok($na)
185 } else if value == SEXP::blank_string() {
186 Ok($blank)
187 } else {
188 let $value = unsafe { root.protect_child(value) }.get();
190 Ok($borrow)
191 }
192 })
193 }
194 }
195 )*};
196}
197
198impl<'a> RootedVecElement<'a> for &'a str {
const NATIVE_BORROW: Option<NativeBorrow> = None;
fn vec_from_root(root: Root<'a>) -> Result<Vec<Self>, SexpError> {
map_strsxp_with(root.get(),
|value, _|
{
if value == SEXP::na_string() {
Ok("")
} else if value == SEXP::blank_string() {
Ok("")
} else {
let value = unsafe { root.protect_child(value) }.get();
Ok(unsafe { charsxp_to_str(value) })
}
})
}
}
impl<'a> RootedVecElement<'a> for Option<&'a str> {
const NATIVE_BORROW: Option<NativeBorrow> = None;
fn vec_from_root(root: Root<'a>) -> Result<Vec<Self>, SexpError> {
map_strsxp_with(root.get(),
|value, _|
{
if value == SEXP::na_string() {
Ok(None)
} else if value == SEXP::blank_string() {
Ok(Some(""))
} else {
let value = unsafe { root.protect_child(value) }.get();
Ok(Some(unsafe { charsxp_to_str(value) }))
}
})
}
}
impl<'a> RootedVecElement<'a> for Cow<'a, str> {
const NATIVE_BORROW: Option<NativeBorrow> = None;
fn vec_from_root(root: Root<'a>) -> Result<Vec<Self>, SexpError> {
map_strsxp_with(root.get(),
|value, _|
{
if value == SEXP::na_string() {
Ok(Cow::Borrowed(""))
} else if value == SEXP::blank_string() {
Ok(Cow::Borrowed(""))
} else {
let value = unsafe { root.protect_child(value) }.get();
Ok(unsafe { charsxp_to_cow(value) })
}
})
}
}
impl<'a> RootedVecElement<'a> for Option<Cow<'a, str>> {
const NATIVE_BORROW: Option<NativeBorrow> = None;
fn vec_from_root(root: Root<'a>) -> Result<Vec<Self>, SexpError> {
map_strsxp_with(root.get(),
|value, _|
{
if value == SEXP::na_string() {
Ok(None)
} else if value == SEXP::blank_string() {
Ok(Some(Cow::Borrowed("")))
} else {
let value = unsafe { root.protect_child(value) }.get();
Ok(Some(unsafe { charsxp_to_cow(value) }))
}
})
}
}character_elements! {'a;
199 &'a str => |value| unsafe { charsxp_to_str(value) }, "", "";
200 Option<&'a str> => |value| Some(unsafe { charsxp_to_str(value) }), None, Some("");
201 Cow<'a, str> => |value| unsafe { charsxp_to_cow(value) }, Cow::Borrowed(""), Cow::Borrowed("");
202 Option<Cow<'a, str>> => |value| Some(unsafe { charsxp_to_cow(value) }), None, Some(Cow::Borrowed(""));
203}
204
205fn rooted_list<'a, T: TryFromRoot<'a>>(root: Root<'a>) -> Result<Vec<T>, SexpError>
208where
209 T::Error: Into<SexpError>,
210{
211 map_vecsxp_batched(root.get(), |value| {
212 T::try_from_root(unsafe { root.protect_child(value) }).map_err(Into::into)
213 })
214}
215
216macro_rules! list_elements {
219 ($life:lifetime, $param:ident: $bound:path; $($element:ty),* $(,)?) => {$(
220 impl<$life, $param: $bound> RootedVecElement<$life> for $element
221 where
222 $element: TryFromRoot<$life>,
223 <$element as TryFromRoot<$life>>::Error: Into<SexpError>,
224 {
225 const NATIVE_BORROW: Option<NativeBorrow> =
226 NativeBorrow::in_list(<$element as TryFromRoot<$life>>::NATIVE_BORROW);
227
228 fn vec_from_root(root: Root<$life>) -> Result<Vec<Self>, SexpError> {
229 rooted_list(root)
230 }
231 }
232 )*};
233}
234
235impl<'a, T: RNativeType> RootedVecElement<'a> for &'a T where
&'a T: TryFromRoot<'a>, <&'a T as TryFromRoot<'a>>::Error: Into<SexpError>
{
const NATIVE_BORROW: Option<NativeBorrow> =
NativeBorrow::in_list(<&'a T as TryFromRoot<'a>>::NATIVE_BORROW);
fn vec_from_root(root: Root<'a>) -> Result<Vec<Self>, SexpError> {
rooted_list(root)
}
}
impl<'a, T: RNativeType> RootedVecElement<'a> for Option<&'a T> where
Option<&'a T>: TryFromRoot<'a>,
<Option<&'a T> as TryFromRoot<'a>>::Error: Into<SexpError> {
const NATIVE_BORROW: Option<NativeBorrow> =
NativeBorrow::in_list(<Option<&'a T> as
TryFromRoot<'a>>::NATIVE_BORROW);
fn vec_from_root(root: Root<'a>) -> Result<Vec<Self>, SexpError> {
rooted_list(root)
}
}
impl<'a, T: RNativeType> RootedVecElement<'a> for &'a [T] where
&'a [T]: TryFromRoot<'a>,
<&'a [T] as TryFromRoot<'a>>::Error: Into<SexpError> {
const NATIVE_BORROW: Option<NativeBorrow> =
NativeBorrow::in_list(<&'a [T] as TryFromRoot<'a>>::NATIVE_BORROW);
fn vec_from_root(root: Root<'a>) -> Result<Vec<Self>, SexpError> {
rooted_list(root)
}
}
impl<'a, T: RNativeType> RootedVecElement<'a> for Option<&'a [T]> where
Option<&'a [T]>: TryFromRoot<'a>,
<Option<&'a [T]> as TryFromRoot<'a>>::Error: Into<SexpError> {
const NATIVE_BORROW: Option<NativeBorrow> =
NativeBorrow::in_list(<Option<&'a [T]> as
TryFromRoot<'a>>::NATIVE_BORROW);
fn vec_from_root(root: Root<'a>) -> Result<Vec<Self>, SexpError> {
rooted_list(root)
}
}list_elements!('a, T: RNativeType; &'a T, Option<&'a T>, &'a [T], Option<&'a [T]>);
236impl<'a, E: RootedVecElement<'a>> RootedVecElement<'a> for Vec<E> where
Vec<E>: TryFromRoot<'a>,
<Vec<E> as TryFromRoot<'a>>::Error: Into<SexpError> {
const NATIVE_BORROW: Option<NativeBorrow> =
NativeBorrow::in_list(<Vec<E> as TryFromRoot<'a>>::NATIVE_BORROW);
fn vec_from_root(root: Root<'a>) -> Result<Vec<Self>, SexpError> {
rooted_list(root)
}
}
impl<'a, E: RootedVecElement<'a>> RootedVecElement<'a> for Option<Vec<E>>
where Option<Vec<E>>: TryFromRoot<'a>,
<Option<Vec<E>> as TryFromRoot<'a>>::Error: Into<SexpError> {
const NATIVE_BORROW: Option<NativeBorrow> =
NativeBorrow::in_list(<Option<Vec<E>> as
TryFromRoot<'a>>::NATIVE_BORROW);
fn vec_from_root(root: Root<'a>) -> Result<Vec<Self>, SexpError> {
rooted_list(root)
}
}list_elements!('a, E: RootedVecElement<'a>; Vec<E>, Option<Vec<E>>);