Skip to main content

interstice_abi/interstice_value/
index_key.rs

1use 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}