Skip to main content

aver/nan_value/
convert.rs

1use super::*;
2use std::collections::HashMap;
3
4use crate::value::Value;
5
6/// Extension trait providing `from_value` / `to_value` conversion between
7/// the runtime `Value` and `NanValue`.  These methods live here
8/// (rather than on `NanValue` directly) because `NanValue` is now defined
9/// in the `aver_memory` crate.
10pub trait NanValueConvert {
11    fn from_value(val: &Value, arena: &mut Arena) -> NanValue;
12    fn to_value(self, arena: &Arena) -> Value;
13}
14
15impl NanValueConvert for NanValue {
16    /// Convert old Value to NanValue, storing heap data in arena.
17    fn from_value(val: &Value, arena: &mut Arena) -> NanValue {
18        match val {
19            Value::Int(i) => NanValue::from_aver_int(i.clone(), arena),
20            Value::Float(f) => NanValue::new_float(*f),
21            Value::Bool(b) => NanValue::new_bool(*b),
22            Value::Unit => NanValue::UNIT,
23            Value::None => NanValue::NONE,
24            Value::Str(s) => NanValue::new_string_value(s, arena),
25            Value::Ok(inner) => {
26                let inner_nv = NanValue::from_value(inner, arena);
27                NanValue::new_ok_value(inner_nv, arena)
28            }
29            Value::Err(inner) => {
30                let inner_nv = NanValue::from_value(inner, arena);
31                NanValue::new_err_value(inner_nv, arena)
32            }
33            Value::Some(inner) => {
34                let inner_nv = NanValue::from_value(inner, arena);
35                NanValue::new_some_value(inner_nv, arena)
36            }
37            Value::Tuple(items) => {
38                let nv_items: Vec<_> = items
39                    .iter()
40                    .map(|v| NanValue::from_value(v, arena))
41                    .collect();
42                NanValue::new_tuple(arena.push_tuple(nv_items))
43            }
44            Value::List(aver_list) => {
45                let items: Vec<_> = aver_list
46                    .to_vec()
47                    .iter()
48                    .map(|v| NanValue::from_value(v, arena))
49                    .collect();
50                if items.is_empty() {
51                    NanValue::EMPTY_LIST
52                } else {
53                    NanValue::new_list(arena.push_list(items))
54                }
55            }
56            Value::Vector(vec) => {
57                let items: Vec<_> = vec.iter().map(|v| NanValue::from_value(v, arena)).collect();
58                if items.is_empty() {
59                    NanValue::EMPTY_VECTOR
60                } else {
61                    NanValue::new_vector(arena.push_vector(items))
62                }
63            }
64            Value::Map(map) => {
65                if map.is_empty() {
66                    return NanValue::EMPTY_MAP;
67                }
68                let mut nv_map = PersistentMap::new();
69                for (k, v) in map {
70                    let nk = NanValue::from_value(k, arena);
71                    let nv = NanValue::from_value(v, arena);
72                    // Use the structural (deep) key hash so it matches the
73                    // hashing scheme every `Map.*` builtin queries with
74                    // (`map.rs::nv_key_bits`). The shallow hash would return
75                    // the arena index for ℤ-overflow int keys (mis-keying).
76                    nv_map = nv_map.insert(nk.map_key_hash_deep(arena), (nk, nv));
77                }
78                let idx = arena.push(ArenaEntry::Map(nv_map));
79                NanValue::new_map(idx)
80            }
81            Value::Fn(f) => NanValue::new_fn(arena.push_fn(Rc::clone(f))),
82            Value::Builtin(name) => NanValue::new_builtin(arena.push_builtin(name)),
83            Value::Record { type_name, fields } => {
84                let type_id = arena.find_type_id(type_name).unwrap_or_else(|| {
85                    let field_names: Vec<String> = fields.iter().map(|(n, _)| n.clone()).collect();
86                    arena.register_record_type(type_name, field_names)
87                });
88                let nv_fields: Vec<_> = fields
89                    .iter()
90                    .map(|(_, v)| NanValue::from_value(v, arena))
91                    .collect();
92                NanValue::new_record(arena.push_record(type_id, nv_fields))
93            }
94            Value::Variant {
95                type_name,
96                variant,
97                fields,
98            } => {
99                let type_id = arena
100                    .find_type_id(type_name)
101                    .unwrap_or_else(|| arena.register_sum_type(type_name, vec![variant.clone()]));
102                let variant_id = arena
103                    .find_variant_id(type_id, variant)
104                    .unwrap_or_else(|| arena.register_variant_name(type_id, variant.clone()));
105                let nv_fields: Vec<_> = fields
106                    .iter()
107                    .map(|v| NanValue::from_value(v, arena))
108                    .collect();
109                if nv_fields.is_empty() {
110                    NanValue::new_nullary_variant(arena.push_nullary_variant_symbol(
111                        arena.find_ctor_id(type_id, variant_id).unwrap(),
112                    ))
113                } else if nv_fields.len() == 1 {
114                    if let Some(ctor_id) = arena.find_ctor_id(type_id, variant_id)
115                        && let Some(iv) = NanValue::try_new_inline_variant(ctor_id, nv_fields[0])
116                    {
117                        return iv;
118                    }
119                    NanValue::new_variant(arena.push_variant(type_id, variant_id, nv_fields))
120                } else {
121                    NanValue::new_variant(arena.push_variant(type_id, variant_id, nv_fields))
122                }
123            }
124            Value::Namespace { name, members } => {
125                let nv_members: Vec<_> = members
126                    .iter()
127                    .map(|(k, v)| (Rc::from(k.as_str()), NanValue::from_value(v, arena)))
128                    .collect();
129                let idx = arena.push(ArenaEntry::Namespace {
130                    name: Rc::from(name.as_str()),
131                    members: nv_members,
132                });
133                NanValue::new_namespace(idx)
134            }
135        }
136    }
137
138    /// Convert NanValue back to old Value (for interop during migration).
139    fn to_value(self, arena: &Arena) -> Value {
140        if self.is_float() {
141            return Value::Float(self.as_float());
142        }
143        if let Some((kind, inner)) = self.wrapper_parts(arena) {
144            let inner = inner.to_value(arena);
145            return match kind {
146                WRAP_SOME => Value::Some(Box::new(inner)),
147                WRAP_OK => Value::Ok(Box::new(inner)),
148                WRAP_ERR => Value::Err(Box::new(inner)),
149                _ => Value::Unit,
150            };
151        }
152        if let Some((type_id, variant_id, inner)) = self.inline_variant_info(arena) {
153            let type_name = arena.get_type_name(type_id).to_string();
154            let variant = arena.get_variant_name(type_id, variant_id).to_string();
155            return Value::Variant {
156                type_name,
157                variant,
158                fields: vec![inner.to_value(arena)].into(),
159            };
160        }
161        if let Some((type_id, variant_id, fields)) = self.variant_parts(arena) {
162            let type_name = arena.get_type_name(type_id).to_string();
163            let variant = arena.get_variant_name(type_id, variant_id).to_string();
164            let vals: Vec<Value> = fields.iter().map(|v| v.to_value(arena)).collect();
165            return Value::Variant {
166                type_name,
167                variant,
168                fields: vals.into(),
169            };
170        }
171        match self.tag() {
172            TAG_INT => Value::Int(self.as_aver_int(arena)),
173            TAG_IMMEDIATE => match self.payload() {
174                IMM_FALSE => Value::Bool(false),
175                IMM_TRUE => Value::Bool(true),
176                IMM_UNIT => Value::Unit,
177                _ => Value::Unit,
178            },
179            TAG_NONE => Value::None,
180            TAG_SOME | TAG_OK | TAG_ERR => {
181                unreachable!("wrapper conversion handled before tag switch")
182            }
183            TAG_STRING => Value::Str(arena.get_string_value(self).to_string()),
184            TAG_LIST => {
185                let vals: Vec<Value> = arena
186                    .list_to_vec_value(self)
187                    .into_iter()
188                    .map(|v| v.to_value(arena))
189                    .collect();
190                Value::List(aver_rt::AverList::from_vec(vals))
191            }
192            TAG_VECTOR => {
193                let items = arena.vector_ref_value(self);
194                let vals: Vec<Value> = items.iter().map(|v| v.to_value(arena)).collect();
195                Value::Vector(aver_rt::AverVector::from_vec(vals))
196            }
197            TAG_TUPLE => {
198                let items = arena.get_tuple(self.arena_index());
199                Value::Tuple(items.iter().map(|v| v.to_value(arena)).collect())
200            }
201            TAG_MAP => {
202                let map = arena.map_ref_value(self);
203                let mut hm = HashMap::new();
204                for (k, v) in map.values() {
205                    hm.insert(k.to_value(arena), v.to_value(arena));
206                }
207                Value::Map(hm)
208            }
209            TAG_RECORD => {
210                let (type_id, fields) = arena.get_record(self.arena_index());
211                let type_name = arena.get_type_name(type_id).to_string();
212                let field_names = arena.get_field_names(type_id);
213                let pairs: Vec<(String, Value)> = field_names
214                    .iter()
215                    .zip(fields)
216                    .map(|(n, v)| (n.clone(), v.to_value(arena)))
217                    .collect();
218                Value::Record {
219                    type_name,
220                    fields: pairs.into(),
221                }
222            }
223            TAG_VARIANT | TAG_INLINE_VARIANT => {
224                unreachable!("variant conversion handled before tag switch")
225            }
226            TAG_SYMBOL => match self.symbol_kind() {
227                SYMBOL_FN => Value::Fn(Rc::clone(arena.get_fn_rc(self.symbol_index()))),
228                SYMBOL_BUILTIN => {
229                    Value::Builtin(arena.get_builtin(self.symbol_index()).to_string())
230                }
231                SYMBOL_NAMESPACE => {
232                    let (name, members) = arena.get_namespace(self.symbol_index());
233                    let mut hm = HashMap::new();
234                    for (k, v) in members {
235                        hm.insert(k.to_string(), v.to_value(arena));
236                    }
237                    Value::Namespace {
238                        name: name.to_string(),
239                        members: hm,
240                    }
241                }
242                SYMBOL_NULLARY_VARIANT => {
243                    unreachable!("variant conversion handled before tag switch")
244                }
245                _ => Value::Unit,
246            },
247            _ => Value::Unit,
248        }
249    }
250}