1use crate::values::lists::List;
2
3use crate::{
4 gc::Gc,
5 rerrs::ErrorKind,
6 rvals::{AsRefSteelValFromUnsized, FromSteelVal, IntoSteelVal, Result},
7 SteelErr, SteelVal,
8};
9use std::{
10 borrow::Cow,
11 collections::{HashMap, HashSet},
12};
13
14use crate::values::HashMap as ImmutableHashMap;
15use crate::values::HashSet as ImmutableHashSet;
16
17#[cfg(feature = "anyhow")]
18mod anyhow_conversion {
19 use crate::{rvals::IntoSteelVal, SteelVal};
20
21 impl IntoSteelVal for anyhow::Error {
22 fn into_steelval(self) -> crate::rvals::Result<crate::SteelVal> {
23 Ok(SteelVal::StringV(format!("{:#?}", self).into()))
24 }
25 }
26}
27
28impl IntoSteelVal for SteelVal {
29 fn into_steelval(self) -> Result<SteelVal> {
30 Ok(self)
31 }
32}
33
34impl FromSteelVal for Gc<ImmutableHashMap<SteelVal, SteelVal>> {
41 fn from_steelval(val: &SteelVal) -> Result<Self> {
42 if let SteelVal::HashMapV(hm) = val {
43 Ok(hm.0.clone())
44 } else {
45 stop!(TypeMismatch => "Unable to convert Steelval to HashMap, found: {}", val);
46 }
47 }
48}
49
50impl IntoSteelVal for Cow<'_, str> {
66 fn into_steelval(self) -> Result<SteelVal> {
67 match self {
68 Cow::Borrowed(b) => b.into_steelval(),
69 Cow::Owned(o) => o.into_steelval(),
70 }
71 }
72}
73
74impl FromSteelVal for Cow<'_, str> {
75 fn from_steelval(val: &SteelVal) -> Result<Self> {
76 if let SteelVal::StringV(s) = val {
77 Ok(Cow::Owned(s.to_string()))
78 } else {
79 stop!(TypeMismatch => "expected string, found {:?}", val)
80 }
81 }
82}
83
84impl<T: IntoSteelVal + Clone> IntoSteelVal for &[T] {
85 fn into_steelval(self) -> Result<SteelVal> {
86 self.iter()
87 .map(|x| x.clone().into_steelval())
88 .collect::<Result<List<_>>>()
89 .map(SteelVal::ListV)
90 }
91}
92
93impl<T: FromSteelVal + Clone> AsRefSteelValFromUnsized<T> for T {
96 type Output = Vec<T>;
97
98 fn as_ref_from_unsized(val: &SteelVal) -> Result<Self::Output> {
99 if let SteelVal::ListV(v) = val {
100 v.iter()
101 .map(|x| T::from_steelval(x))
102 .collect::<Result<Vec<_>>>()
103 } else {
104 stop!(TypeMismatch => "expected list, found: {:?}", val);
105 }
106 }
107}
108
109impl<A: IntoSteelVal, B: IntoSteelVal> IntoSteelVal for (A, B) {
110 fn into_steelval(self) -> Result<SteelVal> {
111 Ok(SteelVal::ListV(
112 vec![self.0.into_steelval()?, self.1.into_steelval()?].into(),
113 ))
114 }
115}
116
117impl<T: IntoSteelVal> IntoSteelVal for Vec<T> {
119 fn into_steelval(self) -> Result<SteelVal> {
120 let vec_vals: Result<Vec<SteelVal>> = self.into_iter().map(|x| x.into_steelval()).collect();
121
122 match vec_vals {
123 Ok(l) => Ok(SteelVal::ListV(l.into())),
124 _ => Err(SteelErr::new(
125 ErrorKind::ConversionError,
126 "Could not convert vector of values to SteelVal list".to_string(),
127 )),
128 }
129 }
130}
131
132impl<T: FromSteelVal> FromSteelVal for Vec<T> {
133 fn from_steelval(val: &SteelVal) -> Result<Self> {
134 match val {
135 SteelVal::ListV(l) => {
136 let result_vec_vals: Result<Self> = l
137 .into_iter()
138 .map(|x| FromSteelVal::from_steelval(x))
139 .collect();
140
141 match result_vec_vals {
142 Ok(x) => Ok(x),
143 _ => Err(SteelErr::new(
144 ErrorKind::ConversionError,
145 "Could not convert SteelVal list to Vector of values".to_string(),
146 )),
147 }
148 }
149 SteelVal::VectorV(v) => {
164 let result_vec_vals: Result<Self> =
165 v.iter().map(FromSteelVal::from_steelval).collect();
166 match result_vec_vals {
167 Ok(x) => Ok(x),
168 _ => Err(SteelErr::new(
169 ErrorKind::ConversionError,
170 "Could not convert SteelVal list to Vector of values".to_string(),
171 )),
172 }
173 } _ => Err(SteelErr::new(
175 ErrorKind::ConversionError,
176 "Could not convert SteelVal list to Vector of values".to_string(),
177 )),
178 }
179 }
180}
181
182impl<T: FromSteelVal> FromSteelVal for Box<[T]> {
183 fn from_steelval(val: &SteelVal) -> Result<Self> {
184 match val {
185 SteelVal::ListV(l) => {
186 let result_vec_vals: Result<Self> = l
187 .into_iter()
188 .map(|x| FromSteelVal::from_steelval(x))
189 .collect();
190
191 match result_vec_vals {
192 Ok(x) => Ok(x),
193 _ => Err(SteelErr::new(
194 ErrorKind::ConversionError,
195 "Could not convert SteelVal list to Vector of values".to_string(),
196 )),
197 }
198 }
199 SteelVal::VectorV(v) => {
200 let result_vec_vals: Result<Self> =
201 v.iter().map(FromSteelVal::from_steelval).collect();
202 match result_vec_vals {
203 Ok(x) => Ok(x),
204 _ => Err(SteelErr::new(
205 ErrorKind::ConversionError,
206 "Could not convert SteelVal list to Vector of values".to_string(),
207 )),
208 }
209 } _ => Err(SteelErr::new(
211 ErrorKind::ConversionError,
212 "Could not convert SteelVal list to Vector of values".to_string(),
213 )),
214 }
215 }
216}
217
218impl FromSteelVal for Box<str> {
219 fn from_steelval(val: &SteelVal) -> Result<Self> {
220 if let SteelVal::StringV(s) = val {
221 Ok(s.as_str().into())
222 } else {
223 stop!(TypeMismatch => "Unable to convert {} into Box<str>", val);
224 }
225 }
226}
227
228impl<K: IntoSteelVal, V: IntoSteelVal> IntoSteelVal for HashMap<K, V> {
230 fn into_steelval(mut self) -> Result<SteelVal> {
231 let mut hm = ImmutableHashMap::new();
232 for (key, val) in self.drain() {
233 hm.insert(key.into_steelval()?, val.into_steelval()?);
234 }
235 Ok(SteelVal::HashMapV(Gc::new(hm).into()))
236 }
237}
238
239impl<K: FromSteelVal + Eq + core::hash::Hash, V: FromSteelVal> FromSteelVal for HashMap<K, V> {
240 fn from_steelval(val: &SteelVal) -> Result<Self> {
241 if let SteelVal::HashMapV(hm) = val {
243 let mut h = HashMap::new();
244 for (key, value) in hm.0.unwrap().into_iter() {
245 h.insert(K::from_steelval(&key)?, V::from_steelval(&value)?);
246 }
247 Ok(h)
248 } else {
249 Err(SteelErr::new(
250 ErrorKind::ConversionError,
251 "Could not convert SteelVal to HashMap".to_string(),
252 ))
253 }
254 }
255}
256
257impl<A: FromSteelVal, B: FromSteelVal> FromSteelVal for (A, B) {
275 fn from_steelval(val: &SteelVal) -> Result<Self> {
276 if let SteelVal::ListV(l) = val {
277 if l.len() != 2 {
278 return Err(SteelErr::new(ErrorKind::ConversionError, format!("Could not convert steelval to (A, B): {:?} - list was not length of 2, found length: {}", val, l.len())));
279 }
280
281 Ok((
282 A::from_steelval(l.get(0).unwrap())?,
283 B::from_steelval(l.get(1).unwrap())?,
284 ))
285 } else {
286 Err(SteelErr::new(
287 ErrorKind::ConversionError,
288 format!("Could not convert SteelVal to (A, B): {:?}", val),
289 ))
290 }
291 }
292}
293
294impl<K: IntoSteelVal> IntoSteelVal for HashSet<K> {
296 fn into_steelval(mut self) -> Result<SteelVal> {
297 let mut hs = ImmutableHashSet::new();
298 for value in self.drain() {
299 hs.insert(value.into_steelval()?);
300 }
301 Ok(SteelVal::HashSetV(Gc::new(hs).into()))
302 }
303}
304
305impl<K: FromSteelVal + Eq + core::hash::Hash> FromSteelVal for HashSet<K> {
306 fn from_steelval(val: &SteelVal) -> Result<Self> {
307 if let SteelVal::HashSetV(hs) = val {
308 let mut h = HashSet::new();
309 for k in hs.0.unwrap().into_iter() {
310 h.insert(K::from_steelval(&k)?);
311 }
312 Ok(h)
313 } else {
314 Err(SteelErr::new(
315 ErrorKind::ConversionError,
316 "Could not convert SteelVal to HashSet".to_string(),
317 ))
318 }
319 }
320}
321
322#[cfg(test)]
336mod conversion_tests {
337
338 use super::*;
339
340 #[cfg(not(feature = "sync"))]
341 use im_rc::vector;
342
343 #[cfg(not(feature = "sync"))]
344 use im_rc::hashmap;
345
346 #[cfg(not(feature = "sync"))]
347 use im_rc::hashset;
348
349 #[cfg(all(feature = "sync", not(feature = "imbl")))]
350 use im::vector;
351
352 #[cfg(all(feature = "sync", not(feature = "imbl")))]
353 use im::hashmap;
354
355 #[cfg(all(feature = "sync", not(feature = "imbl")))]
356 use im::hashset;
357
358 #[cfg(all(feature = "sync", feature = "imbl"))]
359 use steel_imbl::generic_vector as vector;
360
361 #[cfg(all(feature = "sync", feature = "imbl"))]
362 use steel_imbl::generic_hashmap as hashmap;
363
364 #[cfg(all(feature = "sync", feature = "imbl"))]
365 use steel_imbl::generic_hashset as hashset;
366
367 #[test]
368 fn vec_into_list() {
369 let input_vec = vec![1, 2];
370 let expected = SteelVal::ListV(vec![SteelVal::IntV(1), SteelVal::IntV(2)].into());
376
377 assert_eq!(input_vec.into_steelval().unwrap(), expected)
378 }
379
380 #[test]
381 fn vec_from_list() {
382 let input_list = SteelVal::ListV(vec![SteelVal::IntV(1), SteelVal::IntV(2)].into());
383
384 let expected = vec![1, 2];
385 let result = <Vec<i32>>::from_steelval(&input_list).unwrap();
386
387 assert_eq!(result, expected)
388 }
389
390 #[test]
391 fn vec_from_vector() {
392 let input_vector = vector![SteelVal::IntV(1), SteelVal::IntV(2)].into();
393
394 let expected = vec![1, 2];
395 let result = <Vec<i32>>::from_steelval(&input_vector).unwrap();
396 assert_eq!(result, expected);
397 }
398
399 #[test]
400 fn vec_from_steelval_error() {
401 let input = SteelVal::IntV(2);
402 assert!(<Vec<i32>>::from_steelval(&input).is_err());
403 }
404
405 #[test]
406 fn hashmap_into_steelval() {
407 let mut input = HashMap::new();
408 input.insert("foo".to_string(), "bar".to_string());
409 input.insert("foo2".to_string(), "bar2".to_string());
410
411 let expected = SteelVal::HashMapV(
412 Gc::new(hashmap! {
413 SteelVal::StringV("foo".into()) => SteelVal::StringV("bar".into()),
414 SteelVal::StringV("foo2".into()) => SteelVal::StringV("bar2".into())
415 })
416 .into(),
417 );
418
419 assert_eq!(input.into_steelval().unwrap(), expected);
420 }
421
422 #[test]
423 fn hashmap_from_steelval_hashmap() {
424 let input = SteelVal::HashMapV(
425 Gc::new(hashmap! {
426 SteelVal::StringV("foo".into()) => SteelVal::StringV("bar".into()),
427 SteelVal::StringV("foo2".into()) => SteelVal::StringV("bar2".into())
428 })
429 .into(),
430 );
431
432 let mut expected = HashMap::new();
433 expected.insert("foo".to_string(), "bar".to_string());
434 expected.insert("foo2".to_string(), "bar2".to_string());
435
436 assert_eq!(
437 <HashMap<String, String>>::from_steelval(&input).unwrap(),
438 expected
439 );
440 }
441
442 #[test]
443 fn hashset_into_steelval() {
444 let mut input = HashSet::new();
445 input.insert("foo".to_string());
446 input.insert("bar".to_string());
447
448 let expected = SteelVal::HashSetV(
449 Gc::new(hashset! {
450 SteelVal::StringV("foo".into()),
451 SteelVal::StringV("bar".into())
452 })
453 .into(),
454 );
455
456 assert_eq!(input.into_steelval().unwrap(), expected);
457 }
458
459 #[test]
460 fn hashset_from_steelval_hashset() {
461 let input = SteelVal::HashSetV(
462 Gc::new(hashset! {
463 SteelVal::StringV("foo".into()),
464 SteelVal::StringV("bar".into())
465 })
466 .into(),
467 );
468
469 let mut expected = HashSet::new();
470 expected.insert("foo".to_string());
471 expected.insert("bar".to_string());
472
473 assert_eq!(<HashSet<String>>::from_steelval(&input).unwrap(), expected);
474 }
475}