1use std::{any::Any, fmt::Display, mem::ManuallyDrop};
2
3use indexmap::IndexMap;
4use metamatch::metamatch;
5use num::{BigInt, BigRational, FromPrimitive, ToPrimitive};
6
7use crate::{
8 cli::call_expr::Argument,
9 operators::errors::OperatorApplicationError,
10 record_data::field_value_ref::FieldValueSlice,
11 utils::{
12 force_cast,
13 maybe_text::{MaybeText, MaybeTextRef},
14 string_store::StringStoreEntry,
15 text_write::MaybeTextWrite,
16 },
17};
18
19use super::{
20 array::Array,
21 custom_data::CustomDataBox,
22 field::FieldRefOffset,
23 field_data::{FieldValueRepr, FieldValueType, FixedSizeFieldValueType},
24 field_value_ref::{FieldValueRef, FieldValueRefMut},
25 formattable::{Formattable, FormattingContext},
26 scope_manager::OpDeclRef,
27 stream_value::StreamValueId,
28};
29
30#[derive(PartialEq, Eq, Clone, Copy, Debug)]
34pub enum FieldValueKind {
35 Undefined,
36 Null,
37 Int,
38 Float,
39 Error,
40 Bytes,
41 Text,
42 Object,
43 Array,
44 Argument,
45 OpDecl,
46 FieldReference,
47 SlicedFieldReference,
48 StreamValueId,
49 Custom,
50}
51
52impl Display for FieldValueKind {
53 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
54 f.write_str(self.to_str())
55 }
56}
57
58#[derive(Debug, Clone, Default)]
59pub enum FieldValue {
60 #[default]
61 Undefined,
62 Null,
63 Int(i64),
64 BigInt(Box<BigInt>),
65 Float(f64),
66 BigRational(Box<BigRational>),
67 Text(String),
72 Bytes(Vec<u8>), Array(Array),
77 Object(Box<Object>),
78 Custom(CustomDataBox),
79 Error(OperatorApplicationError),
80 OpDecl(OpDeclRef),
81 Argument(Box<Argument>),
82 StreamValueId(StreamValueId),
83 FieldReference(FieldReference),
84 SlicedFieldReference(SlicedFieldReference),
85}
86
87#[derive(Debug, Clone, Default)]
88pub enum FieldValueUnboxed {
89 #[default]
90 Undefined,
91 Null,
92 Int(i64),
93 BigInt(BigInt),
94 Float(f64),
95 BigRational(BigRational),
96 Text(String),
101 Bytes(Vec<u8>), Array(Array),
106 Object(Object),
107 Custom(CustomDataBox),
108 Error(OperatorApplicationError),
109 OpDecl(OpDeclRef),
110 Argument(Argument),
111 StreamValueId(StreamValueId),
112 FieldReference(FieldReference),
113 SlicedFieldReference(SlicedFieldReference),
114}
115
116#[derive(Clone, Copy, Debug, PartialEq, Eq)]
117pub struct Null;
118#[derive(Clone, Copy, Debug, PartialEq, Eq)]
119pub struct Undefined;
120#[derive(Clone, Copy, Debug, PartialEq, Eq)]
121pub struct GroupSeparator;
122
123pub type ObjectKeysStored = IndexMap<String, FieldValue>;
124pub type ObjectKeysInterned = IndexMap<StringStoreEntry, FieldValue>;
125
126#[derive(Debug, Clone, PartialEq)]
127pub enum Object {
128 KeysStored(ObjectKeysStored),
129 KeysInterned(ObjectKeysInterned),
130}
131
132#[derive(Debug, Copy, Clone, PartialEq)]
133pub struct FieldReference {
134 pub field_ref_offset: FieldRefOffset,
135}
136
137#[derive(Debug, Copy, Clone, PartialEq)]
138pub struct SlicedFieldReference {
139 pub field_ref_offset: FieldRefOffset,
140 pub begin: usize,
141 pub end: usize,
142}
143
144impl SlicedFieldReference {
145 pub fn new(
146 field_ref_offset: FieldRefOffset,
147 begin: usize,
148 end: usize,
149 ) -> Self {
150 Self {
151 field_ref_offset,
152 begin,
153 end,
154 }
155 }
156}
157impl FieldReference {
158 pub fn new(field_ref_offset: FieldRefOffset) -> Self {
159 Self { field_ref_offset }
160 }
161}
162
163impl Default for Object {
164 fn default() -> Self {
165 Object::KeysStored(IndexMap::default())
166 }
167}
168
169impl Object {
170 pub fn new_keys_stored() -> Object {
171 Object::KeysStored(IndexMap::default())
172 }
173 pub fn len(&self) -> usize {
174 match self {
175 Object::KeysStored(d) => d.len(),
176 Object::KeysInterned(d) => d.len(),
177 }
178 }
179 pub fn is_empty(&self) -> bool {
180 self.len() == 0
181 }
182
183 pub fn clear(&mut self) {
184 match self {
185 Object::KeysStored(o) => o.clear(),
186 Object::KeysInterned(o) => o.clear(),
187 }
188 }
189 pub fn push_stored_key(&mut self, key: String, value: FieldValue) {
190 if let Object::KeysStored(o) = self {
191 o.insert(key, value);
192 } else {
193 unreachable!()
194 }
195 }
196}
197
198impl FromIterator<(String, FieldValue)> for Object {
199 fn from_iter<I: IntoIterator<Item = (String, FieldValue)>>(
200 iter: I,
201 ) -> Self {
202 Object::KeysStored(IndexMap::from_iter(iter))
203 }
204}
205
206impl FieldValueKind {
207 pub fn repr(&self, inline: bool) -> FieldValueRepr {
208 metamatch!(match self {
209 #[expand((KIND, INLINE, BUFFERED) in [
210 (Text, TextInline, TextBuffer),
211 (Bytes, BytesInline, BytesBuffer),
212 (Int, Int, BigInt),
213 (Float, Float, BigRational)
214 ])]
215 FieldValueKind::KIND => {
216 if inline {
217 FieldValueRepr::INLINE
218 } else {
219 FieldValueRepr::BUFFERED
220 }
221 }
222
223 #[expand(T in [
224 Undefined, Null, Error, Object, Array,
225 Argument, OpDecl, FieldReference,
226 SlicedFieldReference, StreamValueId, Custom
227 ])]
228 FieldValueKind::T => FieldValueRepr::T,
229 })
230 }
231 pub fn to_str(self) -> &'static str {
232 match self {
233 FieldValueKind::Undefined => "undefined",
234 FieldValueKind::Null => "null",
235 FieldValueKind::Int => "int",
236 FieldValueKind::Float => "float",
237 FieldValueKind::Error => "error",
238 FieldValueKind::Text => "str",
239 FieldValueKind::Bytes => "bytes",
240 FieldValueKind::Custom => "custom",
241 FieldValueKind::Object => "object",
242 FieldValueKind::Array => "array",
243 FieldValueKind::FieldReference => "field_reference",
244 FieldValueKind::SlicedFieldReference => "sliced_field_reference",
245 FieldValueKind::StreamValueId => "stream_value_id",
246 FieldValueKind::Argument => "argument",
247 FieldValueKind::OpDecl => "macro",
248 }
249 }
250 pub fn is_valid_utf8(self) -> bool {
251 match self {
252 FieldValueKind::Undefined
253 | FieldValueKind::Null
254 | FieldValueKind::Int
255 | FieldValueKind::Float
256 | FieldValueKind::Error
257 | FieldValueKind::Text
258 | FieldValueKind::Object
259 | FieldValueKind::Array
260 | FieldValueKind::OpDecl => true,
261 FieldValueKind::Bytes
262 | FieldValueKind::FieldReference
263 | FieldValueKind::SlicedFieldReference
264 | FieldValueKind::StreamValueId
265 | FieldValueKind::Custom
266 | FieldValueKind::Argument => false,
267 }
268 }
269}
270
271impl PartialEq for FieldValue {
272 fn eq(&self, other: &Self) -> bool {
273 metamatch!(match self {
274 #[expand(REP in [Null, Undefined])]
275 Self::REP => matches!(other, Self::REP),
276
277 #[expand(REP in [
278 Int, Error, Array, Object, Bytes, Text, OpDecl,
279 FieldReference, SlicedFieldReference, Custom, Float,
280 StreamValueId, BigInt, BigRational, Argument
281 ])]
282 FieldValue::REP(l) => {
283 matches!(other, FieldValue::REP(r) if r == l)
284 }
285 })
286 }
287}
288
289impl FieldValue {
290 pub fn format(
291 &self,
292 ctx: &mut FormattingContext,
293 w: &mut impl MaybeTextWrite,
294 ) -> Result<(), std::io::Error> {
295 self.as_ref().format(ctx, w)
296 }
297 pub fn repr(&self) -> FieldValueRepr {
298 metamatch!(match self {
299 FieldValue::Null => FieldValueRepr::Null,
300 FieldValue::Undefined => FieldValueRepr::Undefined,
301
302 FieldValue::Text(_) => FieldValueRepr::TextBuffer,
303 FieldValue::Bytes(_) => FieldValueRepr::BytesBuffer,
304
305 #[expand(REP in [
306 Int, Error, Array, Object, OpDecl,
307 FieldReference, SlicedFieldReference, Custom, Float,
308 StreamValueId, BigInt, BigRational, Argument
309 ])]
310 FieldValue::REP(_) => FieldValueRepr::REP,
311 })
312 }
313 pub fn downcast_ref<R: FieldValueType>(&self) -> Option<&R> {
314 metamatch!(match self {
315 #[expand(REP in [Null, Undefined])]
316 FieldValue::REP => <dyn Any>::downcast_ref(&REP),
317
318 #[expand(REP in [
319 Int, Error, Array, Object, Text, Bytes, OpDecl,
320 FieldReference, SlicedFieldReference, Custom, Float,
321 StreamValueId, BigInt, BigRational, Argument
322 ])]
323 FieldValue::REP(v) => {
324 if R::FIELD_VALUE_BOXED {
325 <dyn Any>::downcast_ref::<Box<R>>(v).map(|v| &**v)
326 } else {
327 <dyn Any>::downcast_ref(v)
328 }
329 }
330 })
331 }
332 pub fn downcast_mut<R: FieldValueType>(&mut self) -> Option<&mut R> {
333 metamatch!(match self {
334 #[expand(T in [Null, Undefined])]
335 v @ FieldValue::T => <dyn Any>::downcast_mut(v),
336
337 #[expand(REP in [
338 Int, Error, Array, Object, Text, Bytes, OpDecl,
339 FieldReference, SlicedFieldReference, Custom, Float,
340 StreamValueId, BigInt, BigRational, Argument
341 ])]
342 FieldValue::REP(v) => {
343 if R::FIELD_VALUE_BOXED {
344 <dyn Any>::downcast_mut::<Box<R>>(v).map(|v| &mut **v)
345 } else {
346 <dyn Any>::downcast_mut(v)
347 }
348 }
349 })
350 }
351 pub fn as_maybe_text_ref(&self) -> Option<MaybeTextRef> {
352 match self {
353 FieldValue::Text(v) => Some(MaybeTextRef::Text(v)),
354 FieldValue::Bytes(v) => Some(MaybeTextRef::Bytes(v)),
355 FieldValue::Argument(v) => v.value.as_maybe_text_ref(),
356 FieldValue::Undefined
357 | FieldValue::Null
358 | FieldValue::Int(_)
359 | FieldValue::BigInt(_)
360 | FieldValue::Float(_)
361 | FieldValue::BigRational(_)
362 | FieldValue::Array(_)
363 | FieldValue::OpDecl(_)
364 | FieldValue::Object(_)
365 | FieldValue::Custom(_)
366 | FieldValue::Error(_)
367 | FieldValue::StreamValueId(_)
368 | FieldValue::FieldReference(_)
369 | FieldValue::SlicedFieldReference(_) => None,
370 }
371 }
372 pub fn text_or_bytes(&self) -> Option<&[u8]> {
373 self.as_maybe_text_ref().map(|t| t.as_bytes())
374 }
375 pub fn downcast<R: FixedSizeFieldValueType>(self) -> Option<R> {
376 let mut this = ManuallyDrop::new(self);
377 this.downcast_mut().map(|v| unsafe { std::ptr::read(v) })
378 }
379 pub fn downcast_allowing_text_as_bytes<R: FixedSizeFieldValueType>(
380 self,
381 ) -> Option<R> {
382 if let FieldValue::Text(text) = self {
383 if R::REPR != FieldValueRepr::TextBuffer {
384 return FieldValue::Bytes(text.into_bytes()).downcast();
385 }
386 return FieldValue::Text(text).downcast();
387 }
388 let mut this = ManuallyDrop::new(self);
389 this.downcast_mut().map(|v| unsafe { std::ptr::read(v) })
390 }
391 pub fn as_ref(&self) -> FieldValueRef {
392 metamatch!(match self {
393 #[expand(REP in [Null, Undefined])]
394 FieldValue::REP => FieldValueRef::REP,
395
396 #[expand(REP in [
397 Int, Error, Array, Object, Text, Bytes,
398 FieldReference, SlicedFieldReference, Custom, Float,
399 StreamValueId, BigInt, BigRational, Argument, OpDecl
400 ])]
401 FieldValue::REP(v) => FieldValueRef::REP(v),
402 })
403 }
404 pub fn as_slice(&self) -> FieldValueSlice {
408 metamatch!(match self {
409 #[expand(REP in [Null, Undefined])]
410 FieldValue::REP => FieldValueSlice::REP(1),
411
412 #[expand(REP in [
413 Int, Error, Array, Object, OpDecl,
414 FieldReference, SlicedFieldReference, Custom, Float,
415 StreamValueId, BigInt, BigRational, Argument,
416 ])]
417 FieldValue::REP(v) =>
418 FieldValueSlice::REP(std::slice::from_ref(v)),
419
420 #[expand((REP, TGT) in [
421 (Text, TextBuffer),
422 (Bytes, BytesBuffer)])
423 ]
424 FieldValue::REP(v) =>
425 FieldValueSlice::TGT(std::slice::from_ref(v)),
426 })
427 }
428 pub fn as_ref_mut(&mut self) -> FieldValueRefMut {
429 metamatch!(match self {
430 #[expand(REP in [Null, Undefined])]
431 FieldValue::REP => FieldValueRefMut::REP,
432
433 #[expand(REP in [
434 Int, Error, Array, Object,
435 FieldReference, SlicedFieldReference, Custom, Float,
436 StreamValueId, BigInt, BigRational, Argument, OpDecl
437 ])]
438 FieldValue::REP(v) => FieldValueRefMut::REP(v),
439
440 #[expand((VALUE_T, REF_T) in [
441 (Text, TextBuffer),
442 (Bytes, BytesBuffer)
443 ])]
444 FieldValue::VALUE_T(v) => FieldValueRefMut::REF_T(v),
445 })
446 }
447 pub fn from_maybe_text(t: MaybeText) -> Self {
448 match t {
449 MaybeText::Text(t) => FieldValue::Text(t),
450 MaybeText::Bytes(b) => FieldValue::Bytes(b),
451 }
452 }
453 pub fn into_maybe_text(self) -> Option<MaybeText> {
454 match self {
455 FieldValue::Text(t) => Some(MaybeText::Text(t)),
456 FieldValue::Bytes(b) => Some(MaybeText::Bytes(b)),
457 FieldValue::Argument(arg) => arg.value.into_maybe_text(),
458 _ => None,
459 }
460 }
461 pub fn from_fixed_sized_type<T: FixedSizeFieldValueType>(v: T) -> Self {
462 metamatch!(match T::REPR {
467 #[expand(REP in [Null, Undefined])]
468 FieldValueRepr::REP => FieldValue::REP,
469
470 #[expand(REP in [
471 Int, Error, Array, Object,
472 FieldReference, SlicedFieldReference, Custom, Float,
473 StreamValueId, BigInt, BigRational, Argument, OpDecl
474 ])]
475 FieldValueRepr::REP => {
476 if T::FIELD_VALUE_BOXED {
477 FieldValue::REP(unsafe { force_cast(Box::new(v)) })
478 } else {
479 FieldValue::REP(unsafe { force_cast(v) })
480 }
481 }
482
483 #[expand((REP_T, VALUE_T) in [
484 (TextBuffer, Text),
485 (BytesBuffer, Bytes)
486 ])]
487 FieldValueRepr::REP_T => {
488 FieldValue::VALUE_T(unsafe { force_cast(v) })
489 }
490
491 FieldValueRepr::TextInline | FieldValueRepr::BytesInline => {
493 unreachable!()
494 }
495 })
496 }
497 pub fn is_error(&self) -> bool {
498 matches!(self, FieldValue::Error(_))
499 }
500 pub fn kind(&self) -> FieldValueKind {
501 self.repr().kind()
502 }
503 pub fn is_valid_utf8(&self) -> bool {
504 self.kind().is_valid_utf8()
505 }
506 pub fn try_cast_int(&self, fuzzy: bool) -> Option<i64> {
507 match self {
508 FieldValue::Text(_)
509 | FieldValue::Bytes(_)
510 | FieldValue::Float(_)
511 if !fuzzy =>
512 {
513 None
514 }
515
516 FieldValue::Int(v) => Some(*v),
517 FieldValue::BigInt(v) => v.to_i64(),
518
519 #[allow(clippy::cast_precision_loss, clippy::float_cmp)]
520 &FieldValue::Float(f) => {
521 let int = f as i64;
522 if int as f64 == f {
523 return Some(int);
524 }
525 None
526 }
527
528 FieldValue::Text(v) => v.parse().ok(),
529 FieldValue::Bytes(v) => std::str::from_utf8(v).ok()?.parse().ok(),
530
531 FieldValue::BigRational(v) => {
532 if !v.is_integer() {
533 return None;
534 }
535 v.numer().to_i64()
536 }
537
538 FieldValue::Argument(v) => v.value.try_cast_int(fuzzy),
539
540 FieldValue::Undefined
541 | FieldValue::Null
542 | FieldValue::Array(_)
543 | FieldValue::Object(_)
544 | FieldValue::OpDecl(_)
545 | FieldValue::Custom(_)
546 | FieldValue::Error(_)
547 | FieldValue::StreamValueId(_)
548 | FieldValue::FieldReference(_)
549 | FieldValue::SlicedFieldReference(_) => None,
550 }
551 }
552 pub fn try_into_bigint(self, fuzzy: bool) -> Option<BigInt> {
553 match self {
554 FieldValue::Text(_)
555 | FieldValue::Bytes(_)
556 | FieldValue::Float(_)
557 if !fuzzy =>
558 {
559 None
560 }
561
562 FieldValue::Int(v) => Some(BigInt::from(v)),
563 FieldValue::BigInt(v) => Some(*v),
564 FieldValue::Float(f) => {
565 if let Some(v) = BigInt::from_f64(f) {
566 if v.to_f64() == Some(f) {
567 return Some(v);
568 }
569 }
570 None
571 }
572 FieldValue::Text(v) => v.parse().ok(),
573 FieldValue::Bytes(v) => std::str::from_utf8(&v).ok()?.parse().ok(),
574 FieldValue::BigRational(v) => {
575 if !v.is_integer() {
576 return None;
577 }
578 let (numer, _) = v.into_raw();
579 Some(numer)
580 }
581 FieldValue::Argument(v) => v.value.try_into_bigint(fuzzy),
582 FieldValue::Undefined
583 | FieldValue::Null
584 | FieldValue::Array(_)
585 | FieldValue::Object(_)
586 | FieldValue::Custom(_)
587 | FieldValue::Error(_)
588 | FieldValue::OpDecl(_)
589 | FieldValue::StreamValueId(_)
590 | FieldValue::FieldReference(_)
591 | FieldValue::SlicedFieldReference(_) => None,
592 }
593 }
594 pub fn unbox(self) -> FieldValueUnboxed {
595 metamatch!(match self {
596 #[expand(REP in [Null, Undefined])]
597 FieldValue::REP => FieldValueUnboxed::REP,
598
599 #[expand(REP in [
600 Int, Error, Array, OpDecl, Text, Bytes,
601 FieldReference, SlicedFieldReference, Custom, Float,
602 StreamValueId,
603 ])]
604 FieldValue::REP(v) => FieldValueUnboxed::REP(v),
605
606 #[expand(REP in [
607 Object, BigInt, BigRational, Argument,
608 ])]
609 FieldValue::REP(v) => FieldValueUnboxed::REP(*v),
610 })
611 }
612
613 pub fn deref_argument(&self) -> &FieldValue {
614 if let FieldValue::Argument(arg) = self {
615 &arg.value
616 } else {
617 self
618 }
619 }
620 pub fn deref_argument_mut(&mut self) -> &mut FieldValue {
621 if let FieldValue::Argument(arg) = self {
622 &mut arg.value
623 } else {
624 self
625 }
626 }
627}
628
629impl FieldValueUnboxed {
630 pub fn into_field_value(self) -> FieldValue {
631 metamatch!(match self {
632 #[expand(REP in [Null, Undefined])]
633 FieldValueUnboxed::REP => FieldValue::REP,
634
635 #[expand(REP in [
636 Int, Error, Array, OpDecl, Text, Bytes,
637 FieldReference, SlicedFieldReference, Custom, Float,
638 StreamValueId,
639 ])]
640 FieldValueUnboxed::REP(v) => FieldValue::REP(v),
641
642 #[expand(REP in [
643 Object, BigInt, BigRational, Argument,
644 ])]
645 FieldValueUnboxed::REP(v) => FieldValue::REP(Box::new(v)),
646 })
647 }
648}