Skip to main content

klayout_core/
properties.rs

1//! Generic typed key-value store for round-tripping GDS/OASIS user properties
2//! and tagging Component build args on cells.
3//!
4//! Backed by a `Vec` so iteration order is deterministic and cheap to hash.
5
6use smol_str::SmolStr;
7
8#[derive(Clone, Debug, PartialEq)]
9pub enum PropertyValue {
10    Int(i64),
11    Float(f64),
12    String(SmolStr),
13    Bytes(Vec<u8>),
14    List(Vec<PropertyValue>),
15}
16
17impl Eq for PropertyValue {}
18
19impl std::hash::Hash for PropertyValue {
20    fn hash<H: std::hash::Hasher>(&self, h: &mut H) {
21        match self {
22            PropertyValue::Int(i) => {
23                h.write_u8(0);
24                i.hash(h);
25            }
26            PropertyValue::Float(f) => {
27                h.write_u8(1);
28                h.write_u64(f.to_bits());
29            }
30            PropertyValue::String(s) => {
31                h.write_u8(2);
32                s.hash(h);
33            }
34            PropertyValue::Bytes(b) => {
35                h.write_u8(3);
36                b.hash(h);
37            }
38            PropertyValue::List(l) => {
39                h.write_u8(4);
40                l.hash(h);
41            }
42        }
43    }
44}
45
46#[derive(Clone, Debug, Default, PartialEq, Eq, Hash)]
47pub struct Properties {
48    inner: Vec<(SmolStr, PropertyValue)>,
49}
50
51impl Properties {
52    pub fn new() -> Self {
53        Self::default()
54    }
55
56    pub fn is_empty(&self) -> bool {
57        self.inner.is_empty()
58    }
59
60    pub fn len(&self) -> usize {
61        self.inner.len()
62    }
63
64    pub fn set(&mut self, key: impl Into<SmolStr>, value: PropertyValue) {
65        let key = key.into();
66        if let Some(slot) = self.inner.iter_mut().find(|(k, _)| *k == key) {
67            slot.1 = value;
68        } else {
69            self.inner.push((key, value));
70        }
71    }
72
73    pub fn get(&self, key: &str) -> Option<&PropertyValue> {
74        self.inner.iter().find(|(k, _)| k == key).map(|(_, v)| v)
75    }
76
77    pub fn iter(&self) -> impl Iterator<Item = (&SmolStr, &PropertyValue)> {
78        self.inner.iter().map(|(k, v)| (k, v))
79    }
80
81    pub(crate) fn sorted_iter(&self) -> Vec<(&SmolStr, &PropertyValue)> {
82        let mut v: Vec<_> = self.inner.iter().map(|(k, v)| (k, v)).collect();
83        v.sort_by(|a, b| a.0.cmp(b.0));
84        v
85    }
86}