1use crate::{KFunction, Ptr, Result, prelude::*};
4use std::{
5 fmt::{self, Write},
6 result::Result as StdResult,
7};
8
9#[derive(Clone, Default)]
11pub enum KValue {
12 #[default]
14 Null,
15
16 Bool(bool),
18
19 Number(KNumber),
21
22 Range(KRange),
24
25 List(KList),
27
28 Tuple(KTuple),
30
31 Map(KMap),
33
34 Str(KString),
36
37 Function(KFunction),
39
40 NativeFunction(KNativeFunction),
42
43 Iterator(KIterator),
45
46 Object(KObject),
48
49 TemporaryTuple(RegisterSlice),
56}
57
58impl KValue {
59 pub fn deep_copy(&self) -> Result<KValue> {
63 let result = match &self {
64 KValue::List(l) => {
65 let result = l
66 .data()
67 .iter()
68 .map(|v| v.deep_copy())
69 .collect::<Result<_>>()?;
70 KList::with_data(result).into()
71 }
72 KValue::Tuple(t) => {
73 let result = t
74 .iter()
75 .map(|v| v.deep_copy())
76 .collect::<Result<Vec<_>>>()?;
77 KValue::Tuple(result.into())
78 }
79 KValue::Map(m) => {
80 let data = m
81 .data()
82 .iter()
83 .map(|(k, v)| v.deep_copy().map(|v| (k.clone(), v)))
84 .collect::<Result<_>>()?;
85 let meta = m.meta_map().map(|meta| meta.borrow().clone());
86 KMap::with_contents(data, meta).into()
87 }
88 KValue::Iterator(i) => i.make_copy()?.into(),
89 KValue::Object(o) => o.try_borrow()?.copy().into(),
90 _ => self.clone(),
91 };
92
93 Ok(result)
94 }
95
96 pub fn is_callable(&self) -> bool {
98 use KValue::*;
99 match self {
100 Function(f) if f.flags.is_generator() => false,
101 Function(_) | NativeFunction(_) => true,
102 Map(m) => m.contains_meta_key(&MetaKey::Call),
103 Object(o) => o.try_borrow().is_ok_and(|o| o.is_callable()),
104 _ => false,
105 }
106 }
107
108 pub fn is_generator(&self) -> bool {
110 matches!(self, KValue::Function(f) if f.flags.is_generator())
111 }
112
113 pub fn is_hashable(&self) -> bool {
117 use KValue::*;
118 match self {
119 Null | Bool(_) | Number(_) | Range(_) | Str(_) => true,
120 Tuple(t) => t.is_hashable(),
121 _ => false,
122 }
123 }
124
125 pub fn is_indexable(&self) -> bool {
127 use KValue::*;
128 match self {
129 List(_) | Map(_) | Str(_) | Tuple(_) => true,
130 Object(o) => o.try_borrow().is_ok_and(|o| o.size().is_some()),
131 _ => false,
132 }
133 }
134
135 pub fn is_iterable(&self) -> bool {
137 use KValue::*;
138 match self {
139 Range(_) | List(_) | Tuple(_) | Str(_) | Iterator(_) => true,
140 Map(m) => {
141 if m.meta_map().is_some() {
142 m.contains_meta_key(&UnaryOp::Iterator.into())
143 || m.contains_meta_key(&UnaryOp::Next.into())
144 } else {
145 true
146 }
147 }
148 Object(o) => o
149 .try_borrow()
150 .is_ok_and(|o| !matches!(o.is_iterable(), IsIterable::NotIterable)),
151 _ => false,
152 }
153 }
154
155 pub fn is_same_instance(&self, other: &Self) -> bool {
157 use KValue::*;
158 match (self, other) {
159 (Map(a), Map(b)) => a.is_same_instance(b),
160 (Object(a), Object(b)) => a.is_same_instance(b),
161 (List(a), List(b)) => a.is_same_instance(b),
162 (Tuple(a), Tuple(b)) => a.is_same_instance(b),
163 _ => false,
164 }
165 }
166
167 pub fn type_as_string(&self) -> KString {
169 use KValue::*;
170 match &self {
171 Null => TYPE_NULL.with(|x| x.clone()),
172 Bool(_) => TYPE_BOOL.with(|x| x.clone()),
173 Number(_) => TYPE_NUMBER.with(|x| x.clone()),
174 List(_) => TYPE_LIST.with(|x| x.clone()),
175 Range { .. } => TYPE_RANGE.with(|x| x.clone()),
176 Map(m) if m.meta_map().is_some() => m
177 .meta_type()
178 .unwrap_or_else(|| TYPE_OBJECT.with(|x| x.clone())),
179 Map(_) => TYPE_MAP.with(|x| x.clone()),
180 Str(_) => TYPE_STRING.with(|x| x.clone()),
181 Tuple(_) => TYPE_TUPLE.with(|x| x.clone()),
182 Function(f) if f.flags.is_generator() => TYPE_GENERATOR.with(|x| x.clone()),
183 Function(_) | NativeFunction(_) => TYPE_FUNCTION.with(|x| x.clone()),
184 Object(o) => o.try_borrow().map_or_else(
185 |_| "Error: object already borrowed".into(),
186 |o| o.type_string(),
187 ),
188 Iterator(_) => TYPE_ITERATOR.with(|x| x.clone()),
189 TemporaryTuple { .. } => TYPE_TEMPORARY_TUPLE.with(|x| x.clone()),
190 }
191 }
192
193 pub fn display(&self, ctx: &mut DisplayContext) -> Result<()> {
195 use KValue::*;
196 let _ = match self {
197 Null => write!(ctx, "null"),
198 Bool(b) => write!(ctx, "{b}"),
199 Number(n) => write!(ctx, "{n}"),
200 Range(r) => write!(ctx, "{r}"),
201 Function(f) => {
202 if ctx.debug_enabled() {
203 write!(ctx, "|| (chunk: {}, ip: {})", Ptr::address(&f.chunk), f.ip)
204 } else {
205 write!(ctx, "||")
206 }
207 }
208 NativeFunction(f) => {
209 if ctx.debug_enabled() {
210 write!(ctx, "|| ({})", Ptr::address(&f.function))
211 } else {
212 write!(ctx, "||")
213 }
214 }
215 Iterator(_) => write!(ctx, "Iterator"),
216 TemporaryTuple(RegisterSlice { start, count }) => {
217 write!(ctx, "TemporaryTuple [{start}..{}]", start + count)
218 }
219 Str(s) => {
220 if ctx.is_contained() || ctx.debug_enabled() {
221 write!(ctx, "\'{s}\'")
222 } else {
223 write!(ctx, "{s}")
224 }
225 }
226 List(l) => return l.display(ctx),
227 Tuple(t) => return t.display(ctx),
228 Map(m) => return m.display(ctx),
229 Object(o) => return o.try_borrow()?.display(ctx),
230 };
231 Ok(())
232 }
233}
234
235thread_local! {
236 static TYPE_NULL: KString = "Null".into();
237 static TYPE_BOOL: KString = "Bool".into();
238 static TYPE_NUMBER: KString = "Number".into();
239 static TYPE_LIST: KString = "List".into();
240 static TYPE_RANGE: KString = "Range".into();
241 static TYPE_MAP: KString = "Map".into();
242 static TYPE_OBJECT: KString = "Object".into();
243 static TYPE_STRING: KString = "String".into();
244 static TYPE_TUPLE: KString = "Tuple".into();
245 static TYPE_FUNCTION: KString = "Function".into();
246 static TYPE_GENERATOR: KString = "Generator".into();
247 static TYPE_ITERATOR: KString = "Iterator".into();
248 static TYPE_TEMPORARY_TUPLE: KString = "TemporaryTuple".into();
249}
250
251impl fmt::Debug for KValue {
252 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
253 write!(f, "{}", self.type_as_string())
254 }
255}
256
257impl From<()> for KValue {
258 fn from(_: ()) -> Self {
259 Self::Null
260 }
261}
262
263impl From<bool> for KValue {
264 fn from(value: bool) -> Self {
265 Self::Bool(value)
266 }
267}
268
269impl From<KNumber> for KValue {
270 fn from(value: KNumber) -> Self {
271 Self::Number(value)
272 }
273}
274
275impl From<KRange> for KValue {
276 fn from(value: KRange) -> Self {
277 Self::Range(value)
278 }
279}
280
281impl From<&str> for KValue {
282 fn from(value: &str) -> Self {
283 Self::Str(value.into())
284 }
285}
286
287impl From<String> for KValue {
288 fn from(value: String) -> Self {
289 Self::Str(value.into())
290 }
291}
292
293impl From<KString> for KValue {
294 fn from(value: KString) -> Self {
295 Self::Str(value)
296 }
297}
298
299impl From<KList> for KValue {
300 fn from(value: KList) -> Self {
301 Self::List(value)
302 }
303}
304
305impl From<KTuple> for KValue {
306 fn from(value: KTuple) -> Self {
307 Self::Tuple(value)
308 }
309}
310
311impl From<KMap> for KValue {
312 fn from(value: KMap) -> Self {
313 Self::Map(value)
314 }
315}
316
317impl From<KObject> for KValue {
318 fn from(value: KObject) -> Self {
319 Self::Object(value)
320 }
321}
322
323impl From<KIterator> for KValue {
324 fn from(value: KIterator) -> Self {
325 Self::Iterator(value)
326 }
327}
328
329impl From<KNativeFunction> for KValue {
330 fn from(value: KNativeFunction) -> Self {
331 Self::NativeFunction(value)
332 }
333}
334
335impl<T> From<T> for KValue
336where
337 T: KotoFunction,
338{
339 fn from(value: T) -> Self {
340 Self::NativeFunction(KNativeFunction::new(value))
341 }
342}
343
344impl<T> From<Option<T>> for KValue
345where
346 T: Into<KValue>,
347{
348 fn from(value: Option<T>) -> Self {
349 match value {
350 Some(value) => value.into(),
351 None => KValue::Null,
352 }
353 }
354}
355
356#[allow(missing_docs)]
360#[derive(Clone, Copy, Debug, PartialEq, Eq)]
361pub struct RegisterSlice {
362 pub start: u8,
363 pub count: u8,
364}
365
366impl TryFrom<KValue> for bool {
368 type Error = KValue;
369
370 fn try_from(value: KValue) -> StdResult<Self, KValue> {
371 if let KValue::Bool(b) = value {
372 Ok(b)
373 } else {
374 Err(value)
375 }
376 }
377}
378
379macro_rules! impl_try_from_value_string {
380 ($($type:ty),+) => {
381 $(
382 impl TryFrom<KValue> for $type {
384 type Error = KValue;
385
386 fn try_from(value: KValue) -> StdResult<Self, KValue> {
387 if let KValue::Str(s) = value {
388 Ok(s.as_str().into())
389 } else {
390 Err(value)
391 }
392 }
393 }
394 )+
395 };
396}
397
398macro_rules! impl_try_from_value_string_ref {
399 ($($type:ty),+) => {
400 $(
401 impl<'a> TryFrom<&'a KValue> for $type {
403 type Error = &'a KValue;
404
405 fn try_from(value: &'a KValue) -> StdResult<Self, &'a KValue> {
406 if let KValue::Str(s) = value {
407 Ok(s.as_str().into())
408 } else {
409 Err(value)
410 }
411 }
412 }
413 )+
414 };
415}
416
417macro_rules! impl_try_from_value_number {
418 ($($type:ty),+) => {
419 $(
420 impl TryFrom<KValue> for $type {
425 type Error = KValue;
426
427 fn try_from(value: KValue) -> StdResult<Self, KValue> {
428 if let KValue::Number(n) = value {
429 Ok(n.into())
430 } else {
431 Err(value)
432 }
433 }
434 }
435 )+
436 };
437}
438
439impl_try_from_value_string!(String, Box<str>, std::rc::Rc<str>, std::sync::Arc<str>);
440impl_try_from_value_string_ref!(&'a str, std::borrow::Cow<'a, str>);
441impl_try_from_value_number!(
442 f32, f64, i8, u8, i16, u16, i32, u32, i64, u64, i128, u128, isize, usize
443);
444
445#[cfg(test)]
446mod tests {
447 use super::*;
448
449 #[test]
450 fn test_value_mem_size() {
451 assert!(size_of::<KString>() <= 16);
455 assert!(size_of::<KList>() <= 16);
456 assert!(size_of::<KMap>() <= 16);
457 assert!(size_of::<KObject>() <= 16);
458 assert!(size_of::<KFunction>() <= 24);
459 assert!(size_of::<KValue>() <= 24);
460 }
461
462 #[test]
463 fn try_from_kvalue() {
464 assert_eq!(
465 &String::try_from(KValue::from("testing")).unwrap(),
466 "testing"
467 );
468
469 assert_eq!(i32::try_from(KValue::from(-123.45)).unwrap(), -123);
470
471 assert!(matches!(bool::try_from(KValue::Null), Err(KValue::Null)));
472 }
473}