1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
#![allow(clippy::many_single_char_names, clippy::type_complexity)]
use impl_trait_for_tuples::*;
use polar_core::terms::{self, Numeric, Term, Value};
use super::class::Instance;
use super::Host;
use crate::errors::TypeError;
pub trait FromPolar: Clone + Sized + 'static {
fn from_polar(term: &Term, host: &Host) -> crate::Result<Self> {
let wrong_value = match term.value() {
terms::Value::ExternalInstance(terms::ExternalInstance { instance_id, .. }) => {
return host
.get_instance(*instance_id)
.and_then(|instance| {
instance
.downcast::<Self>(Some(&host))
.map_err(|e| e.invariant().into())
})
.map(Clone::clone);
}
val => val,
};
let expected = host
.get_class_from_type::<Self>()
.map(|class| class.name.clone())
.ok()
.unwrap_or_else(|| std::any::type_name::<Self>().to_owned());
let got = match wrong_value {
Value::Number(Numeric::Integer(_)) => Some("Integer"),
Value::Number(Numeric::Float(_)) => Some("Float"),
Value::String(_) => Some("String"),
Value::Boolean(_) => Some("Boolean"),
Value::List(_) => Some("List"),
Value::Dictionary(_) => Some("Dictionary"),
Value::Variable(_) => Some("Variable"),
Value::Call(_) => Some("Predicate"),
_ => None,
};
let mut type_error = TypeError::expected(expected);
if let Some(got) = got {
type_error = type_error.got(got.to_owned());
}
Err(type_error.user())
}
}
mod private {
pub trait Sealed {}
}
pub trait FromPolarList: private::Sealed {
fn from_polar_list(terms: &[Term], host: &Host) -> crate::Result<Self>
where
Self: Sized;
}
impl<T: crate::FromPolarValue> FromPolar for T {
fn from_polar(term: &Term, host: &Host) -> crate::Result<Self> {
T::from_polar_value(crate::PolarValue::from_term(term, host)?)
}
}
impl FromPolar for Instance {
fn from_polar(term: &Term, host: &Host) -> crate::Result<Self> {
let instance = match &term.value() {
terms::Value::Boolean(b) => Instance::new(*b),
terms::Value::Number(terms::Numeric::Integer(i)) => Instance::new(*i),
terms::Value::Number(terms::Numeric::Float(f)) => Instance::new(*f),
terms::Value::List(v) => Instance::new(v.clone()),
terms::Value::String(s) => Instance::new(s.clone()),
terms::Value::Dictionary(d) => Instance::new(d.fields.clone()),
terms::Value::ExternalInstance(terms::ExternalInstance { instance_id, .. }) => host
.get_instance(*instance_id)
.expect("instance not found")
.clone(),
v => {
tracing::warn!(value = ?v, "invalid conversion attempted");
return Err(crate::OsoError::FromPolar);
}
};
Ok(instance)
}
}
#[impl_for_tuples(16)]
#[tuple_types_custom_trait_bound(FromPolar)]
impl FromPolarList for Tuple {
fn from_polar_list(terms: &[Term], host: &Host) -> crate::Result<Self> {
let mut iter = terms.iter();
let result = Ok((for_tuples!(
#( Tuple::from_polar(iter.next().ok_or(
crate::OsoError::FromPolar
)?, host)? ),*
)));
if iter.len() > 0 {
tracing::warn!("Remaining items in iterator after conversion.");
for item in iter {
tracing::trace!("Remaining item {}", item);
}
return Err(crate::OsoError::FromPolar);
}
result
}
}
#[impl_for_tuples(16)]
#[tuple_types_custom_trait_bound(FromPolar)]
impl private::Sealed for Tuple {}