1use crate::AssetId;
2use crate::{HashMap, Schema, SchemaFingerprint, SchemaNamedType, SchemaSet};
3use std::hash::{Hash, Hasher};
4use std::sync::Arc;
5
6use hydrate_schema::{DataSetError, DataSetResult, SchemaEnum};
7
8#[derive(Clone, Debug, PartialEq)]
11pub enum PropertyValue {
12 Boolean(bool),
13 I32(i32),
14 I64(i64),
15 U32(u32),
16 U64(u64),
17 F32(f32),
18 F64(f64),
19 Bytes(Arc<Vec<u8>>),
20 String(Arc<String>),
21 AssetRef(AssetId),
22 Enum(ValueEnum),
23}
24
25impl PropertyValue {
26 pub fn as_value(&self) -> Value {
28 match self {
29 PropertyValue::Boolean(x) => Value::Boolean(*x),
30 PropertyValue::I32(x) => Value::I32(*x),
31 PropertyValue::I64(x) => Value::I64(*x),
32 PropertyValue::U32(x) => Value::U32(*x),
33 PropertyValue::U64(x) => Value::U64(*x),
34 PropertyValue::F32(x) => Value::F32(*x),
35 PropertyValue::F64(x) => Value::F64(*x),
36 PropertyValue::Bytes(x) => Value::Bytes(x.clone()),
37 PropertyValue::String(x) => Value::String(x.clone()),
38 PropertyValue::AssetRef(x) => Value::AssetRef(*x),
39 PropertyValue::Enum(x) => Value::Enum(x.clone()),
40 }
41 }
42
43 pub fn are_matching_property_values(
45 lhs: &Value,
46 rhs: &Value,
47 ) -> bool {
48 match (lhs, rhs) {
49 (Value::Boolean(lhs), Value::Boolean(rhs)) => *lhs == *rhs,
50 (Value::I32(lhs), Value::I32(rhs)) => *lhs == *rhs,
51 (Value::I64(lhs), Value::I64(rhs)) => *lhs == *rhs,
52 (Value::U32(lhs), Value::U32(rhs)) => *lhs == *rhs,
53 (Value::U64(lhs), Value::U64(rhs)) => *lhs == *rhs,
54 (Value::F32(lhs), Value::F32(rhs)) => *lhs == *rhs,
55 (Value::F64(lhs), Value::F64(rhs)) => *lhs == *rhs,
56 (Value::Bytes(lhs), Value::Bytes(rhs)) => *lhs == *rhs,
57 (Value::String(lhs), Value::String(rhs)) => *lhs == *rhs,
58 (Value::AssetRef(lhs), Value::AssetRef(rhs)) => *lhs == *rhs,
59 (Value::Enum(lhs), Value::Enum(rhs)) => *lhs == *rhs,
60 _ => false,
61 }
62 }
63}
64
65#[derive(Clone, Debug, Default)]
67pub struct ValueMap {
68 properties: HashMap<Value, Value>,
69}
70
71impl Hash for ValueMap {
72 fn hash<H: Hasher>(
73 &self,
74 state: &mut H,
75 ) {
76 let mut hash = 0;
77 for (k, v) in &self.properties {
78 let mut inner_hasher = siphasher::sip::SipHasher::default();
79 k.hash(&mut inner_hasher);
80 v.hash(&mut inner_hasher);
81 hash = hash ^ inner_hasher.finish();
82 }
83
84 hash.hash(state);
85 }
86}
87
88#[derive(Clone, Debug, Default)]
90pub struct ValueRecord {
91 properties: HashMap<String, Value>,
92}
93
94impl Hash for ValueRecord {
95 fn hash<H: Hasher>(
96 &self,
97 state: &mut H,
98 ) {
99 let mut hash = 0;
100 for (k, v) in &self.properties {
101 let mut inner_hasher = siphasher::sip::SipHasher::default();
102 k.hash(&mut inner_hasher);
103 v.hash(&mut inner_hasher);
104 hash = hash ^ inner_hasher.finish();
105 }
106
107 hash.hash(state);
108 }
109}
110
111#[derive(Clone, Debug, Default, PartialEq, Hash)]
114pub struct ValueEnum {
115 symbol_name: String,
116}
117
118impl ValueEnum {
119 pub fn new(symbol_name: String) -> Self {
120 ValueEnum { symbol_name }
121 }
122
123 pub fn symbol_name(&self) -> &str {
124 &self.symbol_name
125 }
126}
127
128#[derive(Clone, Debug)]
130pub enum Value {
131 Nullable(Option<Box<Value>>),
132 Boolean(bool),
133 I32(i32),
134 I64(i64),
135 U32(u32),
136 U64(u64),
137 F32(f32),
138 F64(f64),
139 Bytes(Arc<Vec<u8>>),
140 String(Arc<String>),
142 StaticArray(Vec<Value>),
143 DynamicArray(Vec<Value>),
144 Map(ValueMap),
145 AssetRef(AssetId),
146 Record(ValueRecord),
147 Enum(ValueEnum),
148}
149
150impl Hash for Value {
151 fn hash<H: Hasher>(
152 &self,
153 state: &mut H,
154 ) {
155 match self {
156 Value::Nullable(x) => x.hash(state),
157 Value::Boolean(x) => x.hash(state),
158 Value::I32(x) => x.hash(state),
159 Value::I64(x) => x.hash(state),
160 Value::U32(x) => x.hash(state),
161 Value::U64(x) => x.hash(state),
162 Value::F32(x) => x.to_bits().hash(state),
163 Value::F64(x) => x.to_bits().hash(state),
164 Value::Bytes(x) => x.hash(state),
165 Value::String(x) => x.hash(state),
166 Value::StaticArray(x) => x.hash(state),
167 Value::DynamicArray(x) => x.hash(state),
168 Value::Map(x) => x.hash(state),
169 Value::AssetRef(x) => x.hash(state),
170 Value::Record(x) => x.hash(state),
171 Value::Enum(x) => x.hash(state),
172 }
173 }
174}
175
176const DEFAULT_VALUE_NULLABLE: Value = Value::Nullable(None);
177const DEFAULT_VALUE_BOOLEAN: Value = Value::Boolean(false);
178const DEFAULT_VALUE_I32: Value = Value::I32(0);
179const DEFAULT_VALUE_I64: Value = Value::I64(0);
180const DEFAULT_VALUE_U32: Value = Value::U32(0);
181const DEFAULT_VALUE_U64: Value = Value::U64(0);
182const DEFAULT_VALUE_F32: Value = Value::F32(0.0);
183const DEFAULT_VALUE_F64: Value = Value::F64(0.0);
184const DEFAULT_VALUE_ASSET_REF: Value = Value::AssetRef(AssetId::null());
185
186lazy_static::lazy_static! {
187 static ref DEFAULT_VALUE_BYTES: Value = Value::Bytes(Arc::new(Vec::default()));
188 static ref DEFAULT_VALUE_STRING: Value = Value::String(Arc::from(String::default()));
189 static ref DEFAULT_VALUE_STATIC_ARRAY: Value = Value::StaticArray(Default::default());
190 static ref DEFAULT_VALUE_DYNAMIC_ARRAY: Value = Value::DynamicArray(Default::default());
191 static ref DEFAULT_VALUE_MAP: Value = Value::Map(ValueMap::default());
192 static ref DEFAULT_VALUE_RECORD: Value = Value::Record(ValueRecord::default());
193 static ref DEFAULT_VALUE_ENUM: Value = Value::Enum(ValueEnum::default());
194}
195
196impl Value {
197 pub fn default_for_schema<'a>(
201 schema: &Schema,
202 schema_set: &'a SchemaSet,
203 ) -> &'a Self {
204 match schema {
205 Schema::Nullable(_) => &DEFAULT_VALUE_NULLABLE,
206 Schema::Boolean => &DEFAULT_VALUE_BOOLEAN,
207 Schema::I32 => &DEFAULT_VALUE_I32,
208 Schema::I64 => &DEFAULT_VALUE_I64,
209 Schema::U32 => &DEFAULT_VALUE_U32,
210 Schema::U64 => &DEFAULT_VALUE_U64,
211 Schema::F32 => &DEFAULT_VALUE_F32,
212 Schema::F64 => &DEFAULT_VALUE_F64,
213 Schema::Bytes => &DEFAULT_VALUE_BYTES,
214 Schema::String => &DEFAULT_VALUE_STRING,
215 Schema::StaticArray(_) => &DEFAULT_VALUE_STATIC_ARRAY,
216 Schema::DynamicArray(_) => &DEFAULT_VALUE_DYNAMIC_ARRAY,
217 Schema::Map(_) => &DEFAULT_VALUE_MAP,
218 Schema::AssetRef(_) => &DEFAULT_VALUE_ASSET_REF,
219 Schema::Record(_) => &DEFAULT_VALUE_RECORD,
220 Schema::Enum(named_type_id) => {
221 schema_set.default_value_for_enum(*named_type_id).unwrap()
222 }
223 }
224 }
225
226 pub fn matches_schema(
230 &self,
231 schema: &Schema,
232 named_types: &HashMap<SchemaFingerprint, SchemaNamedType>,
233 ) -> bool {
234 match self {
235 Value::Nullable(inner_value) => {
236 match schema {
237 Schema::Nullable(inner_schema) => {
238 if let Some(inner_value) = inner_value {
239 inner_value.matches_schema(inner_schema, named_types)
241 } else {
242 true
244 }
245 }
246 _ => false,
247 }
248 }
249 Value::Boolean(_) => schema.is_boolean(),
250 Value::I32(_) => schema.is_i32(),
251 Value::I64(_) => schema.is_i64(),
252 Value::U32(_) => schema.is_u32(),
253 Value::U64(_) => schema.is_u64(),
254 Value::F32(_) => schema.is_f32(),
255 Value::F64(_) => schema.is_f64(),
256 Value::Bytes(_) => schema.is_bytes(),
257 Value::String(_) => schema.is_string(),
258 Value::StaticArray(inner_values) => match schema {
259 Schema::StaticArray(inner_schema) => {
260 for value in inner_values {
267 if !value.matches_schema(&*inner_schema.item_type(), named_types) {
268 return false;
269 }
270 }
271
272 true
273 }
274 _ => false,
275 },
276 Value::DynamicArray(inner_values) => match schema {
277 Schema::DynamicArray(inner_schema) => {
278 for inner_value in inner_values {
279 if !inner_value.matches_schema(inner_schema.item_type(), named_types) {
280 return false;
281 }
282 }
283
284 true
285 }
286 _ => false,
287 },
288 Value::Map(inner_value) => match schema {
289 Schema::Map(inner_schema) => {
290 for (k, v) in &inner_value.properties {
291 if !k.matches_schema(inner_schema.key_type(), named_types) {
292 return false;
293 }
294
295 if !v.matches_schema(inner_schema.value_type(), named_types) {
296 return false;
297 }
298 }
299
300 true
301 }
302 _ => false,
303 },
304 Value::AssetRef(_) => {
305 schema.is_asset_ref()
307 }
308 Value::Record(inner_value) => {
309 match schema {
312 Schema::Record(named_type_id) => {
313 let named_type = named_types.get(named_type_id).unwrap();
314 match named_type {
315 SchemaNamedType::Record(inner_schema) => {
316 for (k, v) in &inner_value.properties {
318 let mut property_match_found = false;
319 for field in inner_schema.fields() {
320 if field.name() == k {
321 if v.matches_schema(field.field_schema(), named_types) {
322 property_match_found = true;
323 break;
324 } else {
325 return false;
326 }
327 }
328 }
329
330 if !property_match_found {
331 return false;
332 }
333 }
334
335 true
336 }
337 _ => panic!("A Schema::Record fingerprint is matching a named type that isn't a record"),
338 }
339 }
340 _ => false,
341 }
342 }
343 Value::Enum(inner_value) => {
344 match schema {
345 Schema::Enum(named_type_id) => {
346 let named_type = named_types.get(named_type_id).unwrap();
347 match named_type {
348 SchemaNamedType::Enum(inner_schema) => {
349 for option in inner_schema.symbols() {
350 if option.name() == inner_value.symbol_name {
351 return true;
352 }
353 }
354
355 false
356 }
357 _ => panic!("A Schema::Enum fingerprint is matching a named type that isn't a enum"),
358 }
359 }
360 _ => false,
361 }
362 }
363 }
364 }
365
366 pub fn as_property_value(&self) -> Option<PropertyValue> {
369 match self {
370 Value::Boolean(x) => Some(PropertyValue::Boolean(*x)),
371 Value::I32(x) => Some(PropertyValue::I32(*x)),
372 Value::I64(x) => Some(PropertyValue::I64(*x)),
373 Value::U32(x) => Some(PropertyValue::U32(*x)),
374 Value::U64(x) => Some(PropertyValue::U64(*x)),
375 Value::F32(x) => Some(PropertyValue::F32(*x)),
376 Value::F64(x) => Some(PropertyValue::F64(*x)),
377 Value::Bytes(x) => Some(PropertyValue::Bytes(x.clone())),
378 Value::String(x) => Some(PropertyValue::String(x.clone())),
379 Value::AssetRef(x) => Some(PropertyValue::AssetRef(*x)),
380 Value::Enum(x) => Some(PropertyValue::Enum(x.clone())),
381 _ => None,
382 }
383 }
384
385 pub fn is_nullable(&self) -> bool {
389 match self {
390 Value::Nullable(_) => true,
391 _ => false,
392 }
393 }
394
395 pub fn is_null(&self) -> bool {
396 match self {
397 Value::Nullable(None) => true,
398 _ => false,
399 }
400 }
401
402 pub fn as_nullable(&self) -> DataSetResult<Option<&Value>> {
403 Ok(self.try_as_nullable().ok_or(DataSetError::InvalidSchema)?)
404 }
405
406 pub fn try_as_nullable(&self) -> Option<Option<&Value>> {
407 match self {
408 Value::Nullable(x) => Some(x.as_ref().map(|x| x.as_ref())),
409 _ => None,
410 }
411 }
412
413 pub fn set_nullable(
414 &mut self,
415 value: Option<Value>,
416 ) {
417 *self = Value::Nullable(value.map(|x| Box::new(x)))
418 }
419
420 pub fn is_boolean(&self) -> bool {
424 match self {
425 Value::Boolean(_) => true,
426 _ => false,
427 }
428 }
429
430 pub fn as_boolean(&self) -> DataSetResult<bool> {
431 Ok(self.try_as_boolean().ok_or(DataSetError::InvalidSchema)?)
432 }
433
434 pub fn try_as_boolean(&self) -> Option<bool> {
435 match self {
436 Value::Boolean(x) => Some(*x),
437 _ => None,
438 }
439 }
440
441 pub fn set_boolean(
442 &mut self,
443 value: bool,
444 ) {
445 *self = Value::Boolean(value);
446 }
447
448 pub fn is_i32(&self) -> bool {
452 match self {
453 Value::I32(_) => true,
454 _ => false,
455 }
456 }
457
458 pub fn as_i32(&self) -> DataSetResult<i32> {
459 Ok(self.try_as_i32().ok_or(DataSetError::InvalidSchema)?)
460 }
461
462 pub fn try_as_i32(&self) -> Option<i32> {
463 match self {
464 Value::I32(x) => Some(*x as i32),
465 Value::U32(x) => Some(*x as i32),
466 Value::I64(x) => Some(*x as i32),
467 Value::U64(x) => Some(*x as i32),
468 Value::F32(x) => Some(*x as i32),
469 Value::F64(x) => Some(*x as i32),
470 _ => None,
471 }
472 }
473
474 pub fn set_i32(
475 &mut self,
476 value: i32,
477 ) {
478 *self = Value::I32(value);
479 }
480
481 pub fn is_u32(&self) -> bool {
485 match self {
486 Value::U32(_) => true,
487 _ => false,
488 }
489 }
490
491 pub fn as_u32(&self) -> DataSetResult<u32> {
492 Ok(self.try_as_u32().ok_or(DataSetError::InvalidSchema)?)
493 }
494
495 pub fn try_as_u32(&self) -> Option<u32> {
496 match self {
497 Value::I32(x) => Some(*x as u32),
498 Value::U32(x) => Some(*x as u32),
499 Value::I64(x) => Some(*x as u32),
500 Value::U64(x) => Some(*x as u32),
501 Value::F32(x) => Some(*x as u32),
502 Value::F64(x) => Some(*x as u32),
503 _ => None,
504 }
505 }
506
507 pub fn set_u32(
508 &mut self,
509 value: u32,
510 ) {
511 *self = Value::U32(value);
512 }
513
514 pub fn is_i64(&self) -> bool {
518 match self {
519 Value::I64(_) => true,
520 _ => false,
521 }
522 }
523
524 pub fn as_i64(&self) -> DataSetResult<i64> {
525 Ok(self.try_as_i64().ok_or(DataSetError::InvalidSchema)?)
526 }
527
528 pub fn try_as_i64(&self) -> Option<i64> {
529 match self {
530 Value::I32(x) => Some(*x as i64),
531 Value::U32(x) => Some(*x as i64),
532 Value::I64(x) => Some(*x as i64),
533 Value::U64(x) => Some(*x as i64),
534 Value::F32(x) => Some(*x as i64),
535 Value::F64(x) => Some(*x as i64),
536 _ => None,
537 }
538 }
539
540 pub fn set_i64(
541 &mut self,
542 value: i64,
543 ) {
544 *self = Value::I64(value);
545 }
546
547 pub fn is_u64(&self) -> bool {
551 match self {
552 Value::U64(_) => true,
553 _ => false,
554 }
555 }
556
557 pub fn as_u64(&self) -> DataSetResult<u64> {
558 Ok(self.try_as_u64().ok_or(DataSetError::InvalidSchema)?)
559 }
560
561 pub fn try_as_u64(&self) -> Option<u64> {
562 match self {
563 Value::I32(x) => Some(*x as u64),
564 Value::U32(x) => Some(*x as u64),
565 Value::I64(x) => Some(*x as u64),
566 Value::U64(x) => Some(*x as u64),
567 Value::F32(x) => Some(*x as u64),
568 Value::F64(x) => Some(*x as u64),
569 _ => None,
570 }
571 }
572
573 pub fn set_u64(
574 &mut self,
575 value: u64,
576 ) {
577 *self = Value::U64(value);
578 }
579
580 pub fn is_f32(&self) -> bool {
584 match self {
585 Value::F32(_) => true,
586 _ => false,
587 }
588 }
589
590 pub fn as_f32(&self) -> DataSetResult<f32> {
591 Ok(self.try_as_f32().ok_or(DataSetError::InvalidSchema)?)
592 }
593
594 pub fn try_as_f32(&self) -> Option<f32> {
595 match self {
596 Value::I32(x) => Some(*x as f32),
597 Value::U32(x) => Some(*x as f32),
598 Value::I64(x) => Some(*x as f32),
599 Value::U64(x) => Some(*x as f32),
600 Value::F32(x) => Some(*x),
601 Value::F64(x) => Some(*x as f32),
602 _ => None,
603 }
604 }
605
606 pub fn set_f32(
607 &mut self,
608 value: f32,
609 ) {
610 *self = Value::F32(value);
611 }
612
613 pub fn is_f64(&self) -> bool {
617 match self {
618 Value::F64(_) => true,
619 _ => false,
620 }
621 }
622
623 pub fn as_f64(&self) -> DataSetResult<f64> {
624 Ok(self.try_as_f64().ok_or(DataSetError::InvalidSchema)?)
625 }
626
627 pub fn try_as_f64(&self) -> Option<f64> {
628 match self {
629 Value::I32(x) => Some(*x as f64),
630 Value::U32(x) => Some(*x as f64),
631 Value::I64(x) => Some(*x as f64),
632 Value::U64(x) => Some(*x as f64),
633 Value::F32(x) => Some(*x as f64),
634 Value::F64(x) => Some(*x),
635 _ => None,
636 }
637 }
638
639 pub fn set_f64(
640 &mut self,
641 value: f64,
642 ) {
643 *self = Value::F64(value);
644 }
645
646 pub fn is_bytes(&self) -> bool {
650 match self {
651 Value::Bytes(_) => true,
652 _ => false,
653 }
654 }
655
656 pub fn as_bytes(&self) -> DataSetResult<&Arc<Vec<u8>>> {
657 Ok(self.try_as_bytes().ok_or(DataSetError::InvalidSchema)?)
658 }
659
660 pub fn try_as_bytes(&self) -> Option<&Arc<Vec<u8>>> {
661 match self {
662 Value::Bytes(x) => Some(x),
663 _ => None,
664 }
665 }
666 pub fn set_bytes(
667 &mut self,
668 value: Arc<Vec<u8>>,
669 ) {
670 *self = Value::Bytes(value);
671 }
672
673 pub fn is_string(&self) -> bool {
677 match self {
678 Value::String(_) => true,
679 _ => false,
680 }
681 }
682
683 pub fn as_string(&self) -> DataSetResult<&Arc<String>> {
684 Ok(self.try_as_string().ok_or(DataSetError::InvalidSchema)?)
685 }
686
687 pub fn try_as_string(&self) -> Option<&Arc<String>> {
688 match self {
689 Value::String(x) => Some(x),
690 _ => None,
691 }
692 }
693
694 pub fn set_string(
695 &mut self,
696 value: Arc<String>,
697 ) {
698 *self = Value::String(value);
699 }
700
701 pub fn is_asset_ref(&self) -> bool {
717 match self {
718 Value::AssetRef(_) => true,
719 _ => false,
720 }
721 }
722
723 pub fn as_asset_ref(&self) -> DataSetResult<AssetId> {
724 Ok(self.try_as_asset_ref().ok_or(DataSetError::InvalidSchema)?)
725 }
726
727 pub fn try_as_asset_ref(&self) -> Option<AssetId> {
728 match self {
729 Value::AssetRef(x) => Some(*x),
730 _ => None,
731 }
732 }
733
734 pub fn set_asset_ref(
735 &mut self,
736 value: AssetId,
737 ) {
738 *self = Value::AssetRef(value);
739 }
740
741 pub fn is_record(&self) -> bool {
745 match self {
746 Value::Record(_) => true,
747 _ => false,
748 }
749 }
750
751 pub fn as_record(&self) -> DataSetResult<&ValueRecord> {
752 Ok(self.try_as_record().ok_or(DataSetError::InvalidSchema)?)
753 }
754
755 pub fn try_as_record(&self) -> Option<&ValueRecord> {
756 match self {
757 Value::Record(x) => Some(&*x),
758 _ => None,
759 }
760 }
761
762 pub fn set_record(
763 &mut self,
764 value: ValueRecord,
765 ) {
766 *self = Value::Record(value);
767 }
768
769 pub fn is_enum(&self) -> bool {
773 match self {
774 Value::Enum(_) => true,
775 _ => false,
776 }
777 }
778
779 pub fn as_enum(&self) -> DataSetResult<&ValueEnum> {
780 Ok(self.try_as_enum().ok_or(DataSetError::InvalidSchema)?)
781 }
782
783 pub fn try_as_enum(&self) -> Option<&ValueEnum> {
784 match self {
785 Value::Enum(x) => Some(&*x),
786 _ => None,
787 }
788 }
789
790 pub fn set_enum(
791 &mut self,
792 value: ValueEnum,
793 ) {
794 *self = Value::Enum(value);
795 }
796
797 pub fn enum_value_from_string(
801 schema_enum: &SchemaEnum,
802 name: &str,
803 ) -> Option<Value> {
804 schema_enum
805 .find_symbol_from_name(name)
806 .map(|x| Value::Enum(ValueEnum::new(x.name().to_string())))
807 }
808}