mech_core/structures/
enums.rs1use crate::*;
2
3#[derive(Clone, Debug, PartialEq, Eq)]
6pub struct MechEnum {
7 pub id: u64,
8 pub variants: Vec<(u64, Option<Value>)>,
9 pub names: Ref<Dictionary>,
10}
11
12impl MechEnum {
13
14 pub fn name(&self) -> String {
15 let names_brrw = self.names.borrow();
16 names_brrw.get(&self.id).cloned().unwrap_or_else(|| format!("{}", self.id))
17 }
18
19 #[cfg(feature = "pretty_print")]
20 pub fn to_html(&self) -> String {
21 let dict_brrw = self.names.borrow();
22 let mut variants = Vec::new();
23 for (id, value) in &self.variants {
24 let variant_name = dict_brrw
25 .get(id)
26 .map(|name| name.rsplit('/').next().unwrap_or(name).to_string())
27 .unwrap_or_else(|| format!("{}", id));
28 let variant_html = match value {
29 Some(v) => format!(
30 "<span class=\"mech-enum-variant-name\">:{}</span><span class=\"mech-enum-variant-payload\">(<span class=\"mech-enum-variant-value\">{}</span>)</span>",
31 variant_name,
32 v.to_html()
33 ),
34 None => format!("<span class=\"mech-enum-variant-name\">:{}</span>", variant_name),
35 };
36 variants.push(format!("<span class=\"mech-enum-variant\">{}</span>", variant_html));
37 }
38 format!(
39 "<span class=\"mech-enum\">{}</span>",
40 variants.join("<span class=\"mech-enum-variant-sep\"> | </span>")
41 )
42 }
43
44 pub fn kind(&self) -> ValueKind {
45 if self.variants.len() == 1 {
46 let (variant_id, payload) = &self.variants[0];
47 let names_brrw = self.names.borrow();
48 if let Some(variant_name) = names_brrw.get(variant_id) {
49 let short_variant_name = variant_name
50 .rsplit('/')
51 .next()
52 .unwrap_or(variant_name)
53 .to_string();
54 if let Some(value) = payload {
55 if !matches!(value, Value::Kind(_)) {
56 return ValueKind::Enum(
57 self.id,
58 format!("{}({})", short_variant_name, enum_payload_kind(value)),
59 );
60 }
61 }
62 return ValueKind::Enum(self.id, short_variant_name);
63 }
64 }
65 ValueKind::Enum(self.id, self.name())
66 }
67
68 pub fn size_of(&self) -> usize {
69 self.variants.iter().map(|(_,v)| v.as_ref().map_or(0, |x| x.size_of())).sum()
70 }
71}
72
73#[cfg(feature = "pretty_print")]
74impl PrettyPrint for MechEnum {
75 fn pretty_print(&self) -> String {
76 let mut variants = Vec::new();
77 let dict_brrw = self.names.borrow();
78 let enum_name = dict_brrw.get(&self.id).unwrap();
79 for (id, value) in &self.variants {
80 let value_str = match value {
81 Some(v) => v.pretty_print(),
82 None => "None".to_string(),
83 };
84 let variant_name = dict_brrw.get(id).unwrap();
85 variants.push(format!("{}(\n{})", variant_name, value_str));
86 }
87 format!(":{}/{}", enum_name, variants.join(" | "))
88 }
89}
90
91impl Hash for MechEnum {
92 fn hash<H: Hasher>(&self, state: &mut H) {
93 self.id.hash(state);
94 self.variants.hash(state);
95 }
96}
97
98#[derive(Debug, Clone)]
99pub struct UnknownEnumVariantError {
100 pub enum_id: u64,
101 pub given_variant_id: u64,
102}
103impl MechErrorKind for UnknownEnumVariantError {
104 fn name(&self) -> &str { "UnknownEnumVariant" }
105 fn message(&self) -> String {
106 format!(
107 "Unknown variant {} for enum {}",
108 self.given_variant_id, self.enum_id
109 )
110 }
111}
112
113fn enum_payload_kind(value: &Value) -> String {
114 match value {
115 Value::Enum(enum_value) => {
116 let enum_brrw = enum_value.borrow();
117 if enum_brrw.variants.len() == 1 {
118 let (variant_id, payload) = &enum_brrw.variants[0];
119 let names_brrw = enum_brrw.names.borrow();
120 let variant_name = names_brrw
121 .get(variant_id)
122 .map(|name| name.rsplit('/').next().unwrap_or(name).to_string())
123 .unwrap_or_else(|| format!("{}", variant_id));
124 return match payload {
125 Some(inner_payload) => format!(":{}({})", variant_name, enum_payload_kind(inner_payload)),
126 None => format!(":{}", variant_name),
127 };
128 }
129 format!("{}", enum_brrw.kind())
130 }
131 _ => format!("{}", value.kind()),
132 }
133}