interstice_abi/interstice_value/
index_key.rs1use serde::{Deserialize, Serialize};
2
3use super::IntersticeValue;
4
5#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, Eq, Hash)]
6pub enum IndexKey {
7 U8(u8),
8 U32(u32),
9 U64(u64),
10 I32(i32),
11 I64(i64),
12 Bool(bool),
13 String(String),
14 Option(Option<Box<IndexKey>>),
15 Tuple(Vec<IndexKey>),
16}
17
18impl PartialOrd for IndexKey {
19 fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
20 Some(self.cmp(other))
21 }
22}
23
24impl Ord for IndexKey {
25 fn cmp(&self, other: &Self) -> std::cmp::Ordering {
26 use IndexKey::*;
27 let rank = |key: &IndexKey| match key {
28 U8(_) => 0,
29 U32(_) => 1,
30 U64(_) => 2,
31 I32(_) => 3,
32 I64(_) => 4,
33 Bool(_) => 5,
34 String(_) => 6,
35 Option(_) => 7,
36 Tuple(_) => 8,
37 };
38
39 let self_rank = rank(self);
40 let other_rank = rank(other);
41 if self_rank != other_rank {
42 return self_rank.cmp(&other_rank);
43 }
44
45 match (self, other) {
46 (U8(a), U8(b)) => a.cmp(b),
47 (U32(a), U32(b)) => a.cmp(b),
48 (U64(a), U64(b)) => a.cmp(b),
49 (I32(a), I32(b)) => a.cmp(b),
50 (I64(a), I64(b)) => a.cmp(b),
51 (Bool(a), Bool(b)) => a.cmp(b),
52 (String(a), String(b)) => a.cmp(b),
53 (Option(a), Option(b)) => match (a, b) {
54 (None, None) => std::cmp::Ordering::Equal,
55 (None, Some(_)) => std::cmp::Ordering::Less,
56 (Some(_), None) => std::cmp::Ordering::Greater,
57 (Some(a), Some(b)) => a.cmp(b),
58 },
59 (Tuple(a), Tuple(b)) => {
60 for (left, right) in a.iter().zip(b.iter()) {
61 let ord = left.cmp(right);
62 if ord != std::cmp::Ordering::Equal {
63 return ord;
64 }
65 }
66 a.len().cmp(&b.len())
67 }
68 _ => std::cmp::Ordering::Equal,
69 }
70 }
71}
72
73impl TryFrom<&IntersticeValue> for IndexKey {
74 type Error = String;
75
76 fn try_from(value: &IntersticeValue) -> Result<Self, Self::Error> {
77 match value {
78 IntersticeValue::U8(v) => Ok(IndexKey::U8(*v)),
79 IntersticeValue::U32(v) => Ok(IndexKey::U32(*v)),
80 IntersticeValue::U64(v) => Ok(IndexKey::U64(*v)),
81 IntersticeValue::I32(v) => Ok(IndexKey::I32(*v)),
82 IntersticeValue::I64(v) => Ok(IndexKey::I64(*v)),
83 IntersticeValue::Bool(v) => Ok(IndexKey::Bool(*v)),
84 IntersticeValue::String(v) => Ok(IndexKey::String(v.clone())),
85 IntersticeValue::Option(v) => match v {
86 Some(inner) => Ok(IndexKey::Option(Some(Box::new(IndexKey::try_from(
87 inner.as_ref(),
88 )?)))),
89 None => Ok(IndexKey::Option(None)),
90 },
91 IntersticeValue::Tuple(items) => {
92 let mut converted = Vec::with_capacity(items.len());
93 for item in items {
94 converted.push(IndexKey::try_from(item)?);
95 }
96 Ok(IndexKey::Tuple(converted))
97 }
98 IntersticeValue::Void => Err("Void value cannot be used as an index key".to_string()),
99 IntersticeValue::F32(_) | IntersticeValue::F64(_) => {
100 Err("Float values cannot be used as index keys".to_string())
101 }
102 IntersticeValue::Vec(_)
103 | IntersticeValue::Struct { .. }
104 | IntersticeValue::Enum { .. } => Err(
105 "Only primitive, Option, and Tuple values are supported as index keys".to_string(),
106 ),
107 }
108 }
109}
110
111impl TryFrom<IntersticeValue> for IndexKey {
112 type Error = String;
113
114 fn try_from(value: IntersticeValue) -> Result<Self, Self::Error> {
115 IndexKey::try_from(&value)
116 }
117}
118
119impl From<IndexKey> for IntersticeValue {
120 fn from(value: IndexKey) -> Self {
121 match value {
122 IndexKey::U8(v) => IntersticeValue::U8(v),
123 IndexKey::U32(v) => IntersticeValue::U32(v),
124 IndexKey::U64(v) => IntersticeValue::U64(v),
125 IndexKey::I32(v) => IntersticeValue::I32(v),
126 IndexKey::I64(v) => IntersticeValue::I64(v),
127 IndexKey::Bool(v) => IntersticeValue::Bool(v),
128 IndexKey::String(v) => IntersticeValue::String(v),
129 IndexKey::Option(v) => IntersticeValue::Option(v.map(|inner| {
130 let converted: IntersticeValue = (*inner).into();
131 Box::new(converted)
132 })),
133 IndexKey::Tuple(items) => {
134 IntersticeValue::Tuple(items.into_iter().map(IntersticeValue::from).collect())
135 }
136 }
137 }
138}