Skip to main content

mech_core/structures/
enums.rs

1use crate::*;
2
3// Enum -----------------------------------------------------------------------
4
5#[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}