1use std::{collections::HashMap, fmt::Display, hash::Hash, sync::Arc};
2
3use indexmap::IndexMap;
4
5use crate::{
6 errors::BrdbSchemaError,
7 schema::{BrdbInterned, BrdbSchema, as_brdb::AsBrdbValue},
8 wrapper::Vector3f,
9};
10
11#[derive(Clone, Debug)]
12pub struct BrdbEnum {
13 pub(crate) schema: Arc<BrdbSchema>,
14 pub name: BrdbInterned,
15 pub value: u64,
16}
17
18#[derive(Clone, Debug)]
19pub struct BrdbStruct {
20 pub(crate) schema: Arc<BrdbSchema>,
21 pub name: BrdbInterned,
22 pub properties: HashMap<BrdbInterned, BrdbValue>,
23}
24
25impl BrdbStruct {
26 pub fn get(&self, prop: impl AsRef<str>) -> Option<&BrdbValue> {
27 let key = self.schema.intern.get(prop.as_ref())?;
28 self.properties.get(&key)
29 }
30
31 pub fn contains_key(&self, prop: impl AsRef<str>) -> bool {
32 let Some(key) = self.schema.intern.get(prop.as_ref()) else {
33 return false;
34 };
35 self.properties.contains_key(&key)
36 }
37
38 pub fn get_name(&self) -> &str {
39 self.schema
40 .intern
41 .lookup_ref(self.name)
42 .unwrap_or("unknown")
43 }
44
45 pub fn prop(&self, prop: impl AsRef<str>) -> Result<&BrdbValue, BrdbSchemaError> {
46 let prop = prop.as_ref();
47 self.get(prop).ok_or_else(|| {
48 BrdbSchemaError::MissingStructField(
49 self.schema
50 .intern
51 .lookup(self.name)
52 .unwrap_or_else(|| "unknown struct".to_string()),
53 prop.to_owned(),
54 )
55 })
56 }
57
58 pub fn set_prop(
59 &mut self,
60 prop: impl AsRef<str>,
61 value: BrdbValue,
62 ) -> Result<(), BrdbSchemaError> {
63 let prop = prop.as_ref();
64 let key = self.schema.intern.get(prop).ok_or_else(|| {
65 BrdbSchemaError::MissingStructField(
66 self.schema
67 .intern
68 .lookup(self.name)
69 .unwrap_or_else(|| "unknown struct".to_string()),
70 prop.to_owned(),
71 )
72 })?;
73 if !self.properties.contains_key(&key) {
75 return Err(BrdbSchemaError::MissingStructField(
76 self.schema
77 .intern
78 .lookup(self.name)
79 .unwrap_or_else(|| "unknown struct".to_string()),
80 prop.to_owned(),
81 ));
82 }
83 self.properties.insert(key, value);
84 Ok(())
85 }
86
87 pub fn as_hashmap(&self) -> Result<HashMap<String, Box<dyn AsBrdbValue>>, BrdbSchemaError> {
88 let mut map = HashMap::new();
89 for (k, v) in &self.properties {
90 let key = k
91 .get_ok(&self.schema, || {
92 BrdbSchemaError::MissingStructField(
93 self.name.get_or(&self.schema, "unknown struct").to_string(),
94 "unknown_prop".to_string(),
95 )
96 })?
97 .to_string();
98 map.insert(key, Box::new(v.clone()) as Box<dyn AsBrdbValue>);
99 }
100 Ok(map)
101 }
102
103 pub fn to_value(self) -> BrdbValue {
104 BrdbValue::Struct(Box::new(self.clone()))
105 }
106}
107
108impl From<BrdbStruct> for BrdbValue {
109 fn from(value: BrdbStruct) -> Self {
110 BrdbValue::Struct(Box::new(value))
111 }
112}
113
114impl Display for BrdbStruct {
115 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
116 let mut props = self
117 .properties
118 .iter()
119 .map(|(k, v)| {
120 format!(
121 " {}: {},\n",
122 k.get_or(&self.schema, "unknown_prop"),
123 v.display_inner(&self.schema, 1)
124 )
125 })
126 .collect::<Vec<_>>();
127 props.sort();
128 write!(
129 f,
130 "{} {{\n{}}}",
131 self.name.get_or(&self.schema, "unknown struct"),
132 props.join("")
133 )
134 }
135}
136
137impl BrdbEnum {
138 pub fn get_value_raw(&self) -> u64 {
139 self.value
140 }
141
142 pub fn get_name(&self) -> &str {
143 self.schema
144 .intern
145 .lookup_ref(self.name)
146 .unwrap_or("unknown")
147 }
148
149 pub fn get_value(&self) -> String {
150 self.schema
151 .intern
152 .lookup(self.name)
153 .unwrap_or_else(|| "unknown".to_string())
154 }
155}
156
157#[derive(Clone, Debug)]
158pub enum BrdbValue {
159 Nil,
160 Bool(bool),
161 U8(u8),
162 U16(u16),
163 U32(u32),
164 U64(u64),
165 I8(i8),
166 I16(i16),
167 I32(i32),
168 I64(i64),
169 F32(f32),
170 F64(f64),
171 String(String),
172 Asset(Option<usize>),
173 Enum(BrdbEnum),
174 Struct(Box<BrdbStruct>),
175 Array(Vec<BrdbValue>),
176 FlatArray(Vec<BrdbValue>),
177 Map(IndexMap<BrdbValue, BrdbValue>),
178 WireVar(WireVariant),
179}
180
181#[derive(Clone, Debug)]
186pub enum WireVariant {
187 Number(f64),
188 Int(i64),
189 Bool(bool),
190 Object(Option<usize>),
193 Exec,
194 Vector(Vector3f),
196 Rotator { pitch: f64, yaw: f64, roll: f64 },
198 Quat { x: f64, y: f64, z: f64, w: f64 },
200 Str(String),
202 LinearColor { r: f32, g: f32, b: f32, a: f32 },
204}
205impl Default for WireVariant {
206 fn default() -> Self {
207 WireVariant::Number(0.0)
208 }
209}
210impl Display for WireVariant {
211 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
212 match self {
213 WireVariant::Number(n) => write!(f, "{n}"),
214 WireVariant::Int(i) => write!(f, "{i}"),
215 WireVariant::Bool(b) => write!(f, "{b}"),
216 WireVariant::Object(Some(i)) => write!(f, "obj#{i}"),
217 WireVariant::Object(None) => write!(f, "obj#null"),
218 WireVariant::Exec => write!(f, "exec"),
219 WireVariant::Vector(v) => write!(f, "({}, {}, {})", v.x, v.y, v.z),
220 WireVariant::Rotator { pitch, yaw, roll } => {
221 write!(f, "rot({pitch}, {yaw}, {roll})")
222 }
223 WireVariant::Quat { x, y, z, w } => write!(f, "quat({x}, {y}, {z}, {w})"),
224 WireVariant::Str(s) => write!(f, "{s:?}"),
225 WireVariant::LinearColor { r, g, b, a } => {
226 write!(f, "color({r}, {g}, {b}, {a})")
227 }
228 }
229 }
230}
231impl From<f64> for WireVariant {
232 fn from(value: f64) -> Self {
233 WireVariant::Number(value)
234 }
235}
236impl From<f32> for WireVariant {
237 fn from(value: f32) -> Self {
238 WireVariant::Number(value as f64)
239 }
240}
241
242macro_rules! wire_var_int {
243 ($ty:ty) => {
244 impl From<$ty> for WireVariant {
245 fn from(value: $ty) -> Self {
246 WireVariant::Int(value as i64)
247 }
248 }
249 };
250 ($ty:ty, $($rest:ty),*) => {
251 wire_var_int!($ty);
252 wire_var_int!($($rest),*);
253 };
254}
255wire_var_int!(i8, i16, i32, i64, u8, u16, u32, u64);
256
257impl From<bool> for WireVariant {
258 fn from(value: bool) -> Self {
259 WireVariant::Bool(value)
260 }
261}
262impl From<String> for WireVariant {
263 fn from(value: String) -> Self {
264 WireVariant::Str(value)
265 }
266}
267impl From<&str> for WireVariant {
268 fn from(value: &str) -> Self {
269 WireVariant::Str(value.to_string())
270 }
271}
272impl From<Vector3f> for WireVariant {
273 fn from(value: Vector3f) -> Self {
274 WireVariant::Vector(value)
275 }
276}
277
278impl TryFrom<&BrdbValue> for WireVariant {
282 type Error = BrdbSchemaError;
283 fn try_from(value: &BrdbValue) -> Result<Self, Self::Error> {
284 Ok(match value {
285 BrdbValue::WireVar(v) => v.clone(),
286 BrdbValue::F64(n) => WireVariant::Number(*n),
287 BrdbValue::F32(n) => WireVariant::Number(*n as f64),
288 BrdbValue::I64(i) => WireVariant::Int(*i),
289 BrdbValue::I32(i) => WireVariant::Int(*i as i64),
290 BrdbValue::Bool(b) => WireVariant::Bool(*b),
291 BrdbValue::String(s) => WireVariant::Str(s.clone()),
292 BrdbValue::Asset(opt) => WireVariant::Object(*opt),
293 BrdbValue::Struct(s) if s.get_name() == "Vector" => {
294 WireVariant::Vector(Vector3f::try_from(value)?)
295 }
296 other => {
297 return Err(BrdbSchemaError::ExpectedType(
298 "wire variant".to_owned(),
299 other.get_type().to_owned(),
300 ));
301 }
302 })
303 }
304}
305
306#[derive(Clone, Debug, PartialEq)]
310pub enum WireArrayVariant {
311 DoubleArray(Vec<f64>),
313 Int64Array(Vec<i64>),
315 BoolArray(Vec<bool>),
317 ObjectArray(Vec<Option<usize>>),
319 VectorArray(Vec<Vector3f>),
321 RotatorArray(Vec<(f64, f64, f64)>),
323 QuatArray(Vec<(f64, f64, f64, f64)>),
325 StringArray(Vec<String>),
327 LinearColorArray(Vec<(f32, f32, f32, f32)>),
329}
330
331impl WireArrayVariant {
332 pub fn member_type(&self) -> &'static str {
334 match self {
335 WireArrayVariant::DoubleArray(_) => "WireGraphDoubleArray",
336 WireArrayVariant::Int64Array(_) => "WireGraphInt64Array",
337 WireArrayVariant::BoolArray(_) => "WireGraphBoolArray",
338 WireArrayVariant::ObjectArray(_) => "WireGraphObjectArray",
339 WireArrayVariant::VectorArray(_) => "WireGraphVectorArray",
340 WireArrayVariant::RotatorArray(_) => "WireGraphRotatorArray",
341 WireArrayVariant::QuatArray(_) => "WireGraphQuatArray",
342 WireArrayVariant::StringArray(_) => "WireGraphStringArray",
343 WireArrayVariant::LinearColorArray(_) => "WireGraphLinearColorArray",
344 }
345 }
346}
347
348#[derive(Clone, Copy, Debug, PartialEq, Eq)]
351pub enum WireMapKey {
352 Int64,
354 Str,
356 Object,
358}
359
360#[derive(Clone, Copy, Debug, PartialEq, Eq)]
362pub enum WireMapValue {
363 Number,
365 Int64,
367 Bool,
369 Object,
371 Vector,
373 Rotator,
375 Quat,
377 Str,
379 LinearColor,
381}
382
383#[derive(Clone, Debug, PartialEq)]
385pub enum WireMapKeyData {
386 Int64(i64),
387 Str(String),
388 Object(Option<u32>),
390}
391
392#[derive(Clone, Debug, PartialEq)]
394pub enum WireMapValueData {
395 Number(f64),
396 Int64(i64),
397 Bool(bool),
398 Str(String),
399 Vector(Vector3f),
400 Rotator(f64, f64, f64),
401 Quat(f64, f64, f64, f64),
402 LinearColor(f32, f32, f32, f32),
403 Object(Option<u32>),
404}
405
406impl From<WireVariant> for WireMapValueData {
415 fn from(v: WireVariant) -> Self {
416 match v {
417 WireVariant::Number(f) => WireMapValueData::Number(f),
418 WireVariant::Int(i) => WireMapValueData::Int64(i),
419 WireVariant::Bool(b) => WireMapValueData::Bool(b),
420 WireVariant::Str(s) => WireMapValueData::Str(s),
421 WireVariant::Object(o) => WireMapValueData::Object(o.map(|i| i as u32)),
422 WireVariant::Vector(vec) => WireMapValueData::Vector(vec),
423 WireVariant::Rotator { pitch, yaw, roll } => {
424 WireMapValueData::Rotator(pitch, yaw, roll)
425 }
426 WireVariant::Quat { x, y, z, w } => WireMapValueData::Quat(x, y, z, w),
427 WireVariant::LinearColor { r, g, b, a } => WireMapValueData::LinearColor(r, g, b, a),
428 WireVariant::Exec => WireMapValueData::Number(0.0),
430 }
431 }
432}
433
434impl From<WireMapValueData> for WireVariant {
435 fn from(v: WireMapValueData) -> Self {
436 match v {
437 WireMapValueData::Number(f) => WireVariant::Number(f),
438 WireMapValueData::Int64(i) => WireVariant::Int(i),
439 WireMapValueData::Bool(b) => WireVariant::Bool(b),
440 WireMapValueData::Str(s) => WireVariant::Str(s),
441 WireMapValueData::Vector(vec) => WireVariant::Vector(vec),
442 WireMapValueData::Rotator(pitch, yaw, roll) => {
443 WireVariant::Rotator { pitch, yaw, roll }
444 }
445 WireMapValueData::Quat(x, y, z, w) => WireVariant::Quat { x, y, z, w },
446 WireMapValueData::LinearColor(r, g, b, a) => WireVariant::LinearColor { r, g, b, a },
447 WireMapValueData::Object(o) => WireVariant::Object(o.map(|i| i as usize)),
448 }
449 }
450}
451
452impl From<WireVariant> for WireMapKeyData {
453 fn from(v: WireVariant) -> Self {
454 match v {
455 WireVariant::Int(i) => WireMapKeyData::Int64(i),
456 WireVariant::Str(s) => WireMapKeyData::Str(s),
457 WireVariant::Object(o) => WireMapKeyData::Object(o.map(|i| i as u32)),
458 WireVariant::Number(f) => WireMapKeyData::Int64(f as i64),
461 WireVariant::Bool(b) => WireMapKeyData::Int64(b as i64),
462 WireVariant::Vector(_)
463 | WireVariant::Rotator { .. }
464 | WireVariant::Quat { .. }
465 | WireVariant::LinearColor { .. }
466 | WireVariant::Exec => WireMapKeyData::Int64(0),
467 }
468 }
469}
470
471impl From<WireMapKeyData> for WireVariant {
472 fn from(k: WireMapKeyData) -> Self {
473 match k {
474 WireMapKeyData::Int64(i) => WireVariant::Int(i),
475 WireMapKeyData::Str(s) => WireVariant::Str(s),
476 WireMapKeyData::Object(o) => WireVariant::Object(o.map(|i| i as usize)),
477 }
478 }
479}
480
481#[derive(Clone, Debug, PartialEq)]
485pub struct WireMapVariant {
486 pub key: WireMapKey,
487 pub value: WireMapValue,
488 pub entries: Vec<(WireMapKeyData, WireMapValueData)>,
489}
490
491impl WireMapVariant {
492 pub fn key_wrapper(&self) -> &'static str {
494 match self.key {
495 WireMapKey::Int64 => "WireGraphMapKeyWrapper_int64",
496 WireMapKey::Str => "WireGraphMapKeyWrapper_FWireGraphString",
497 WireMapKey::Object => "WireGraphMapKeyWrapper_FWeakObjectPtr",
498 }
499 }
500 pub fn inner_variant(&self) -> &'static str {
502 match self.key {
503 WireMapKey::Int64 => "WireGraphMapVariant_int64",
504 WireMapKey::Str => "WireGraphMapVariant_FWireGraphString",
505 WireMapKey::Object => "WireGraphMapVariant_FWeakObjectPtr",
506 }
507 }
508 pub fn map_struct(&self) -> String {
510 let k = match self.key {
511 WireMapKey::Int64 => "int64",
512 WireMapKey::Str => "FWireGraphString",
513 WireMapKey::Object => "FWeakObjectPtr",
514 };
515 let v = match self.value {
516 WireMapValue::Number => "double",
517 WireMapValue::Int64 => "int64",
518 WireMapValue::Bool => "bool",
519 WireMapValue::Object => "FWeakObjectPtr",
520 WireMapValue::Vector => "FVector",
521 WireMapValue::Rotator => "FRotator",
522 WireMapValue::Quat => "FQuat",
523 WireMapValue::Str => "FWireGraphString",
524 WireMapValue::LinearColor => "FLinearColor",
525 };
526 format!("WireGraphMap_{k}_{v}")
527 }
528}
529
530impl From<Vec<f64>> for WireArrayVariant {
531 fn from(v: Vec<f64>) -> Self {
532 WireArrayVariant::DoubleArray(v)
533 }
534}
535impl From<Vec<i64>> for WireArrayVariant {
536 fn from(v: Vec<i64>) -> Self {
537 WireArrayVariant::Int64Array(v)
538 }
539}
540impl From<Vec<bool>> for WireArrayVariant {
541 fn from(v: Vec<bool>) -> Self {
542 WireArrayVariant::BoolArray(v)
543 }
544}
545impl From<Vec<Vector3f>> for WireArrayVariant {
546 fn from(v: Vec<Vector3f>) -> Self {
547 WireArrayVariant::VectorArray(v)
548 }
549}
550impl From<Vec<String>> for WireArrayVariant {
551 fn from(v: Vec<String>) -> Self {
552 WireArrayVariant::StringArray(v)
553 }
554}
555
556impl TryFrom<&BrdbValue> for WireArrayVariant {
558 type Error = BrdbSchemaError;
559 fn try_from(value: &BrdbValue) -> Result<Self, Self::Error> {
560 let s = value.as_struct()?;
561 let values = s.prop("Values")?.as_array()?;
562 Ok(match s.get_name() {
563 "WireGraphDoubleArray" => WireArrayVariant::DoubleArray(
564 values.iter().map(|v| v.as_brdb_f64()).collect::<Result<_, _>>()?,
565 ),
566 "WireGraphInt64Array" => WireArrayVariant::Int64Array(
567 values.iter().map(|v| v.as_brdb_i64()).collect::<Result<_, _>>()?,
568 ),
569 "WireGraphBoolArray" => WireArrayVariant::BoolArray(
570 values.iter().map(|v| v.as_brdb_bool()).collect::<Result<_, _>>()?,
571 ),
572 "WireGraphStringArray" => WireArrayVariant::StringArray(
573 values
574 .iter()
575 .map(|v| v.as_brdb_str().map(str::to_owned))
576 .collect::<Result<_, _>>()?,
577 ),
578 "WireGraphVectorArray" => WireArrayVariant::VectorArray(
579 values.iter().map(Vector3f::try_from).collect::<Result<_, _>>()?,
580 ),
581 "WireGraphRotatorArray" => WireArrayVariant::RotatorArray(
582 values
583 .iter()
584 .map(|v| {
585 let s = v.as_struct()?;
586 Ok((
587 s.prop("Pitch")?.as_brdb_f64()?,
588 s.prop("Yaw")?.as_brdb_f64()?,
589 s.prop("Roll")?.as_brdb_f64()?,
590 ))
591 })
592 .collect::<Result<_, BrdbSchemaError>>()?,
593 ),
594 "WireGraphQuatArray" => WireArrayVariant::QuatArray(
595 values
596 .iter()
597 .map(|v| {
598 let s = v.as_struct()?;
599 Ok((
600 s.prop("X")?.as_brdb_f64()?,
601 s.prop("Y")?.as_brdb_f64()?,
602 s.prop("Z")?.as_brdb_f64()?,
603 s.prop("W")?.as_brdb_f64()?,
604 ))
605 })
606 .collect::<Result<_, BrdbSchemaError>>()?,
607 ),
608 "WireGraphLinearColorArray" => WireArrayVariant::LinearColorArray(
609 values
610 .iter()
611 .map(|v| {
612 let s = v.as_struct()?;
613 Ok((
614 s.prop("R")?.as_brdb_f32()?,
615 s.prop("G")?.as_brdb_f32()?,
616 s.prop("B")?.as_brdb_f32()?,
617 s.prop("A")?.as_brdb_f32()?,
618 ))
619 })
620 .collect::<Result<_, BrdbSchemaError>>()?,
621 ),
622 "WireGraphObjectArray" => WireArrayVariant::ObjectArray(
623 values
624 .iter()
625 .map(|v| match v {
626 BrdbValue::Asset(opt) => Ok(*opt),
627 other => Err(BrdbSchemaError::ExpectedType(
628 "weak_object".to_owned(),
629 other.get_type().to_owned(),
630 )),
631 })
632 .collect::<Result<_, _>>()?,
633 ),
634 other => return Err(BrdbSchemaError::UnknownType(other.to_owned())),
635 })
636 }
637}
638
639impl BrdbValue {
640 pub fn get_type(&self) -> &'static str {
641 match self {
642 BrdbValue::Nil => "nil",
643 BrdbValue::Bool(_) => "bool",
644 BrdbValue::U8(_) => "u8",
645 BrdbValue::U16(_) => "u16",
646 BrdbValue::U32(_) => "u32",
647 BrdbValue::U64(_) => "u64",
648 BrdbValue::I8(_) => "i8",
649 BrdbValue::I16(_) => "i16",
650 BrdbValue::I32(_) => "i32",
651 BrdbValue::I64(_) => "i64",
652 BrdbValue::F32(_) => "f32",
653 BrdbValue::F64(_) => "f64",
654 BrdbValue::String(_) => "string",
655 BrdbValue::Asset(_) => "asset",
656 BrdbValue::Enum(_) => "enum",
657 BrdbValue::Struct(_) => "struct",
658 BrdbValue::Array(_) => "array",
659 BrdbValue::FlatArray(_) => "flatarray",
660 BrdbValue::Map(_) => "map",
661 BrdbValue::WireVar(_) => "wire_variant",
662 }
663 }
664 pub fn as_struct(&self) -> Result<&BrdbStruct, BrdbSchemaError> {
665 if let Self::Struct(v) = self {
666 Ok(v)
667 } else {
668 Err(BrdbSchemaError::ExpectedType(
669 "struct".to_owned(),
670 self.get_type().to_string(),
671 ))
672 }
673 }
674
675 pub fn prop(&self, prop: impl AsRef<str>) -> Result<&BrdbValue, BrdbSchemaError> {
676 let prop = prop.as_ref();
677 let s = self.as_struct()?;
678 s.get(prop).ok_or_else(|| {
679 BrdbSchemaError::MissingStructField(
680 s.schema
681 .intern
682 .lookup(s.name)
683 .unwrap_or_else(|| "unknown struct".to_string()),
684 prop.to_owned(),
685 )
686 })
687 }
688
689 pub fn contains_key(&self, prop: impl AsRef<str>) -> bool {
690 let Some(s) = self.as_struct().ok() else {
691 return false;
692 };
693 s.contains_key(prop)
694 }
695
696 pub fn as_array(&self) -> Result<&Vec<BrdbValue>, BrdbSchemaError> {
697 match self {
698 Self::Array(v) | Self::FlatArray(v) => Ok(v),
699 _ => Err(BrdbSchemaError::ExpectedType(
700 "array".to_owned(),
701 self.get_type().to_string(),
702 )),
703 }
704 }
705
706 pub fn index(&self, index: usize) -> Result<Option<&BrdbValue>, BrdbSchemaError> {
707 Ok(self.as_array()?.get(index))
708 }
709
710 pub fn index_unwrap(&self, index: usize) -> Result<&BrdbValue, BrdbSchemaError> {
711 let vec = self.as_array()?;
712 Ok(vec
713 .get(index)
714 .ok_or_else(|| BrdbSchemaError::ArrayIndexOutOfBounds {
715 len: vec.len(),
716 index,
717 })?)
718 }
719
720 pub fn as_str(&self) -> Result<&str, BrdbSchemaError> {
721 if let Self::String(v) = self {
722 Ok(v)
723 } else {
724 Err(BrdbSchemaError::ExpectedType(
725 "string".to_owned(),
726 self.get_type().to_string(),
727 ))
728 }
729 }
730
731 pub fn display(&self, schema: &BrdbSchema) -> String {
732 self.display_inner(schema, 0)
733 }
734
735 fn display_inner(&self, schema: &BrdbSchema, depth: usize) -> String {
736 match self {
737 BrdbValue::Nil => "nil".to_string(),
738 BrdbValue::Bool(v) => format!("{v}"),
739 BrdbValue::U8(v) => format!("{v}u8"),
740 BrdbValue::U16(v) => format!("{v}u16"),
741 BrdbValue::U32(v) => format!("{v}u32"),
742 BrdbValue::U64(v) => format!("{v}u64"),
743 BrdbValue::I8(v) => format!("{v}i8"),
744 BrdbValue::I16(v) => format!("{v}i16"),
745 BrdbValue::I32(v) => format!("{v}i32"),
746 BrdbValue::I64(v) => format!("{v}i64"),
747 BrdbValue::F32(v) => format!("{v}f32"),
748 BrdbValue::F64(v) => format!("{v}f64"),
749 BrdbValue::WireVar(v) => match v {
750 WireVariant::Number(n) => format!("wire {n}f64"),
751 WireVariant::Int(i) => format!("wire {i}i64"),
752 WireVariant::Bool(b) => format!("wire {b}"),
753 WireVariant::Object(o) => format!("wire obj#{o:?}"),
754 WireVariant::Exec => "w exec".to_string(),
755 WireVariant::Vector(v) => format!("wire ({}, {}, {})", v.x, v.y, v.z),
756 WireVariant::Rotator { pitch, yaw, roll } => {
757 format!("wire rot({pitch}, {yaw}, {roll})")
758 }
759 WireVariant::Quat { x, y, z, w } => format!("wire quat({x}, {y}, {z}, {w})"),
760 WireVariant::Str(s) => format!("wire {s:?}"),
761 WireVariant::LinearColor { r, g, b, a } => {
762 format!("wire color({r}, {g}, {b}, {a})")
763 }
764 },
765 BrdbValue::String(v) => format!("\"{v}\""),
766 BrdbValue::Asset(None) => "none".to_string(),
767 BrdbValue::Asset(Some(v)) => {
768 if let Some((asset_ty, asset_name)) =
769 schema.global_data.external_asset_references.get_index(*v)
770 {
771 format!("{asset_ty}/{asset_name}")
772 } else {
773 format!("unknown asset {v}")
774 }
775 }
776 BrdbValue::Enum(e) => format!("{}::{}", e.get_name(), e.get_value()),
777 BrdbValue::Struct(s) => {
778 let pad = " ".repeat(depth);
779 let mut props = s
780 .properties
781 .iter()
782 .map(|(k, v)| {
783 format!(
784 "{pad} {}: {},\n",
785 schema.intern.lookup_ref(*k).unwrap_or("unknown prop"),
786 v.display_inner(schema, depth + 1)
787 )
788 })
789 .collect::<Vec<_>>();
790 props.sort();
791 format!(
792 "{} {{\n{}{pad}}}",
793 schema.intern.lookup_ref(s.name).unwrap_or("unknown struct"),
794 props.join("")
795 )
796 }
797 BrdbValue::Array(v) => {
798 let pad = " ".repeat(depth);
799 let elems = v
800 .iter()
801 .map(|e| format!("{pad} {},\n", e.display_inner(schema, depth + 1)))
802 .collect::<Vec<_>>();
803 format!("[\n{}{}]", elems.join(""), " ".repeat(depth))
804 }
805 BrdbValue::FlatArray(v) => {
806 let pad = " ".repeat(depth);
807 let elems = v
808 .iter()
809 .map(|e| format!("{pad} {},\n", e.display_inner(schema, depth + 1)))
810 .collect::<Vec<_>>();
811 format!("flat[\n{}{}]", elems.join(""), " ".repeat(depth))
812 }
813 BrdbValue::Map(map) => {
814 let pad = " ".repeat(depth);
815 let mut entries = map
816 .iter()
817 .map(|(k, v)| {
818 format!(
819 "{pad} {}: {},\n",
820 k.display_inner(schema, depth + 1),
821 v.display_inner(schema, depth + 1)
822 )
823 })
824 .collect::<Vec<_>>();
825 entries.sort();
826 format!("{{\n{}\n{pad}}}", entries.join(""))
827 }
828 }
829 }
830}
831
832impl Hash for BrdbValue {
833 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
834 core::mem::discriminant(self).hash(state);
835 match self {
836 BrdbValue::Nil => {}
837 BrdbValue::Bool(v) => v.hash(state),
838 BrdbValue::U8(v) => v.hash(state),
839 BrdbValue::U16(v) => v.hash(state),
840 BrdbValue::U32(v) => v.hash(state),
841 BrdbValue::U64(v) => v.hash(state),
842 BrdbValue::I8(v) => v.hash(state),
843 BrdbValue::I16(v) => v.hash(state),
844 BrdbValue::I32(v) => v.hash(state),
845 BrdbValue::I64(v) => v.hash(state),
846 BrdbValue::F32(v) => v.to_bits().hash(state),
847 BrdbValue::F64(v) => v.to_bits().hash(state),
848 BrdbValue::String(v) => v.hash(state),
849 BrdbValue::Asset(v) => v.hash(state),
850 BrdbValue::Enum(e) => {
851 e.name.hash(state);
852 e.value.hash(state);
853 }
854 BrdbValue::Struct(s) => {
855 s.name.hash(state);
856 for (k, v) in &s.properties {
857 k.hash(state);
858 v.hash(state);
859 }
860 }
861 BrdbValue::Array(v) => v.hash(state),
862 BrdbValue::FlatArray(v) => v.hash(state),
863 BrdbValue::Map(map) => map.iter().for_each(|(k, v)| {
864 k.hash(state);
865 v.hash(state);
866 }),
867 BrdbValue::WireVar(w) => match w {
868 WireVariant::Number(n) => n.to_bits().hash(state),
869 WireVariant::Int(i) => i.hash(state),
870 WireVariant::Bool(b) => b.hash(state),
871 WireVariant::Object(o) => o.hash(state),
872 WireVariant::Exec => {}
873 WireVariant::Vector(v) => {
874 v.x.to_bits().hash(state);
875 v.y.to_bits().hash(state);
876 v.z.to_bits().hash(state);
877 }
878 WireVariant::Rotator { pitch, yaw, roll } => {
879 pitch.to_bits().hash(state);
880 yaw.to_bits().hash(state);
881 roll.to_bits().hash(state);
882 }
883 WireVariant::Quat { x, y, z, w } => {
884 x.to_bits().hash(state);
885 y.to_bits().hash(state);
886 z.to_bits().hash(state);
887 w.to_bits().hash(state);
888 }
889 WireVariant::Str(s) => s.hash(state),
890 WireVariant::LinearColor { r, g, b, a } => {
891 r.to_bits().hash(state);
892 g.to_bits().hash(state);
893 b.to_bits().hash(state);
894 a.to_bits().hash(state);
895 }
896 },
897 }
898 }
899}
900
901impl Eq for BrdbValue {}
902
903impl PartialEq for BrdbValue {
904 fn eq(&self, other: &Self) -> bool {
905 match (self, other) {
906 (Self::Bool(l0), Self::Bool(r0)) => l0 == r0,
907 (Self::U8(l0), Self::U8(r0)) => l0 == r0,
908 (Self::U16(l0), Self::U16(r0)) => l0 == r0,
909 (Self::U32(l0), Self::U32(r0)) => l0 == r0,
910 (Self::U64(l0), Self::U64(r0)) => l0 == r0,
911 (Self::I8(l0), Self::I8(r0)) => l0 == r0,
912 (Self::I16(l0), Self::I16(r0)) => l0 == r0,
913 (Self::I32(l0), Self::I32(r0)) => l0 == r0,
914 (Self::I64(l0), Self::I64(r0)) => l0 == r0,
915 (Self::F32(l0), Self::F32(r0)) => l0 == r0,
916 (Self::F64(l0), Self::F64(r0)) => l0 == r0,
917 (Self::String(l0), Self::String(r0)) => l0 == r0,
918 (Self::Asset(l0), Self::Asset(r0)) => l0 == r0,
919 (Self::Enum(l0), Self::Enum(r0)) => l0.name == r0.name && l0.value == r0.value,
920 (Self::Struct(l0), Self::Struct(r0)) => {
921 if l0.name != r0.name {
922 return false;
923 }
924 for (k, lv) in &l0.properties {
926 let Some(kv) = r0.properties.get(k) else {
927 return false;
928 };
929 if lv != kv {
930 return false;
931 }
932 }
933 return true;
934 }
935 (Self::Array(l0), Self::Array(r0)) => l0 == r0,
936 (Self::FlatArray(l0), Self::FlatArray(r0)) => l0 == r0,
937 (Self::Map(l0), Self::Map(r0)) => l0 == r0,
938 (Self::WireVar(l0), Self::WireVar(r0)) => match (l0, r0) {
939 (WireVariant::Number(l), WireVariant::Number(r)) => l == r,
940 (WireVariant::Int(l), WireVariant::Int(r)) => l == r,
941 (WireVariant::Bool(l), WireVariant::Bool(r)) => l == r,
942 (WireVariant::Object(l), WireVariant::Object(r)) => l == r,
943 (WireVariant::Exec, WireVariant::Exec) => false,
944 (WireVariant::Vector(l), WireVariant::Vector(r)) => l == r,
945 (WireVariant::Str(l), WireVariant::Str(r)) => l == r,
946 _ => false,
947 },
948 _ => core::mem::discriminant(self) == core::mem::discriminant(other),
949 }
950 }
951}
952
953impl TryFrom<&BrdbValue> for String {
954 type Error = BrdbSchemaError;
955
956 fn try_from(value: &BrdbValue) -> Result<Self, Self::Error> {
957 value.as_str().map(|s| s.to_string())
958 }
959}
960impl TryFrom<BrdbValue> for String {
961 type Error = BrdbSchemaError;
962
963 fn try_from(value: BrdbValue) -> Result<Self, Self::Error> {
964 match value {
965 BrdbValue::String(s) => Ok(s),
966 _ => Err(BrdbSchemaError::ExpectedType(
967 "string".to_owned(),
968 value.get_type().to_string(),
969 )),
970 }
971 }
972}
973
974impl<'a> TryFrom<&'a BrdbValue> for &'a str {
975 type Error = BrdbSchemaError;
976
977 fn try_from(value: &'a BrdbValue) -> Result<&'a str, Self::Error> {
978 if let BrdbValue::String(v) = value {
979 Ok(v.as_ref())
980 } else {
981 Err(BrdbSchemaError::ExpectedType(
982 "string".to_owned(),
983 value.get_type().to_string(),
984 ))
985 }
986 }
987}
988
989impl<'a, T: TryFrom<&'a BrdbValue, Error = BrdbSchemaError>> TryFrom<&'a BrdbValue> for Vec<T> {
990 type Error = BrdbSchemaError;
991
992 fn try_from(value: &'a BrdbValue) -> Result<Self, Self::Error> {
993 let array = value.as_array()?;
994 let mut vec = Vec::with_capacity(array.len());
995 for item in array {
996 vec.push(T::try_from(item)?);
997 }
998 Ok(vec)
999 }
1000}
1001
1002impl<T: TryFrom<BrdbValue, Error = BrdbSchemaError>> TryFrom<BrdbValue> for Vec<T> {
1003 type Error = BrdbSchemaError;
1004
1005 fn try_from(value: BrdbValue) -> Result<Self, Self::Error> {
1006 let array = match value {
1007 BrdbValue::Array(v) => v,
1008 BrdbValue::FlatArray(v) => v,
1009 _ => {
1010 return Err(BrdbSchemaError::ExpectedType(
1011 "array".to_owned(),
1012 value.get_type().to_string(),
1013 ));
1014 }
1015 };
1016 let mut vec = Vec::with_capacity(array.len());
1017 for item in array {
1018 vec.push(T::try_from(item)?);
1019 }
1020 Ok(vec)
1021 }
1022}
1023
1024macro_rules! try_from_impl(
1025 ($id:ident @ $ty:ty) => {
1026 impl TryFrom<&BrdbValue> for $ty {
1027 type Error = BrdbSchemaError;
1028
1029 fn try_from(value: &BrdbValue) -> Result<Self, Self::Error> {
1030 value.$id()
1031 }
1032 }
1033 impl TryFrom<BrdbValue> for $ty {
1034 type Error = BrdbSchemaError;
1035
1036 fn try_from(value: BrdbValue) -> Result<Self, Self::Error> {
1037 value.$id()
1038 }
1039 }
1040
1041 }
1042);
1043
1044try_from_impl!(as_brdb_bool @ bool);
1045try_from_impl!(as_brdb_u8 @ u8);
1046try_from_impl!(as_brdb_u16 @ u16);
1047try_from_impl!(as_brdb_u32 @ u32);
1048try_from_impl!(as_brdb_u64 @ u64);
1049try_from_impl!(as_brdb_i8 @ i8);
1050try_from_impl!(as_brdb_i16 @ i16);
1051try_from_impl!(as_brdb_i32 @ i32);
1052try_from_impl!(as_brdb_i64 @ i64);
1053try_from_impl!(as_brdb_f32 @ f32);
1054try_from_impl!(as_brdb_f64 @ f64);
1055
1056#[cfg(test)]
1057mod wire_map_conversion_tests {
1058 use super::*;
1059
1060 #[test]
1061 fn map_value_data_round_trips_through_wire_variant() {
1062 let cases = [
1063 WireMapValueData::Number(1.5),
1064 WireMapValueData::Int64(-7),
1065 WireMapValueData::Bool(true),
1066 WireMapValueData::Str("hi".into()),
1067 WireMapValueData::Vector(Vector3f { x: 1.0, y: 2.0, z: 3.0 }),
1068 WireMapValueData::Rotator(10.0, 20.0, 30.0),
1069 WireMapValueData::Quat(0.0, 0.0, 0.0, 1.0),
1070 WireMapValueData::LinearColor(0.1, 0.2, 0.3, 1.0),
1071 WireMapValueData::Object(Some(5)),
1072 WireMapValueData::Object(None),
1073 ];
1074 for v in cases {
1075 let round: WireMapValueData = WireVariant::from(v.clone()).into();
1076 assert_eq!(round, v);
1077 }
1078 }
1079
1080 #[test]
1081 fn map_key_data_round_trips_through_wire_variant() {
1082 let cases = [
1083 WireMapKeyData::Int64(42),
1084 WireMapKeyData::Str("k".into()),
1085 WireMapKeyData::Object(Some(3)),
1086 WireMapKeyData::Object(None),
1087 ];
1088 for k in cases {
1089 let round: WireMapKeyData = WireVariant::from(k.clone()).into();
1090 assert_eq!(round, k);
1091 }
1092 }
1093
1094 #[test]
1095 fn wire_variant_forward_conversions_and_fallbacks() {
1096 assert_eq!(WireMapValueData::from(WireVariant::Int(9)), WireMapValueData::Int64(9));
1098 assert_eq!(
1099 WireMapKeyData::from(WireVariant::Str("s".into())),
1100 WireMapKeyData::Str("s".into())
1101 );
1102 assert_eq!(WireMapValueData::from(WireVariant::Exec), WireMapValueData::Number(0.0));
1104 assert_eq!(WireMapKeyData::from(WireVariant::Number(3.9)), WireMapKeyData::Int64(3));
1105 assert_eq!(WireMapKeyData::from(WireVariant::Bool(true)), WireMapKeyData::Int64(1));
1106 assert_eq!(
1107 WireMapKeyData::from(WireVariant::Vector(Vector3f { x: 0.0, y: 0.0, z: 0.0 })),
1108 WireMapKeyData::Int64(0)
1109 );
1110 }
1111}