rune/runtime/value/
rtti.rs

1use core::borrow::Borrow;
2use core::cmp::Ordering;
3use core::hash;
4
5#[cfg(feature = "musli")]
6use musli::{Decode, Encode};
7#[cfg(feature = "serde")]
8use serde::{Deserialize, Serialize};
9
10use crate::alloc::prelude::*;
11use crate::alloc::HashMap;
12use crate::item::Item;
13use crate::runtime::{FieldMap, TypeInfo, Value};
14use crate::sync::Arc;
15use crate::{Hash, ItemBuf};
16
17/// Field accessor for a variant struct.
18#[doc(hidden)]
19pub struct Accessor<'a> {
20    pub(crate) fields: &'a HashMap<Box<str>, usize>,
21    pub(crate) data: &'a [Value],
22}
23
24impl Accessor<'_> {
25    /// Get a field through the accessor.
26    #[doc(hidden)]
27    pub fn get<Q>(&self, key: &Q) -> Option<&Value>
28    where
29        Box<str>: Borrow<Q>,
30        Q: hash::Hash + Eq + ?Sized,
31    {
32        self.data.get(*self.fields.get(key)?)
33    }
34}
35
36/// The kind of value stored.
37#[derive(Debug, Clone, Copy)]
38#[cfg_attr(
39    feature = "serde",
40    derive(Serialize, Deserialize),
41    serde(rename_all = "kebab-case")
42)]
43#[cfg_attr(feature = "musli", derive(Encode, Decode))]
44pub(crate) enum RttiKind {
45    /// The value stored is empty.
46    Empty,
47    /// The value stored is a tuple.
48    Tuple,
49    /// The value stored is a strict.
50    Struct,
51}
52
53/// Runtime information on variant.
54#[derive(Debug)]
55#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
56#[cfg_attr(feature = "musli", derive(Encode, Decode))]
57#[non_exhaustive]
58pub struct Rtti {
59    /// The kind of value.
60    pub(crate) kind: RttiKind,
61    /// The type hash of the type.
62    pub(crate) hash: Hash,
63    /// If this type is a variant, designates the hash of the variant.
64    pub(crate) variant_hash: Hash,
65    /// The item of the type.
66    pub(crate) item: ItemBuf,
67    /// Mapping from field names to their corresponding indexes.
68    pub(crate) fields: FieldMap<Box<str>, usize>,
69}
70
71impl Rtti {
72    /// Test if this RTTI matches the given raw hashes.
73    #[inline]
74    pub(crate) fn is(&self, hash: Hash, variant_hash: Hash) -> bool {
75        self.hash == hash && self.variant_hash == variant_hash
76    }
77
78    /// Access the item of the RTTI.
79    #[inline]
80    pub fn item(&self) -> &Item {
81        &self.item
82    }
83
84    /// Access the type hash of the RTTI.
85    #[inline]
86    pub fn type_hash(&self) -> Hash {
87        self.hash
88    }
89
90    /// Access the type information for the RTTI.
91    #[inline]
92    pub fn type_info(this: Arc<Self>) -> TypeInfo {
93        TypeInfo::rtti(this)
94    }
95}
96
97impl PartialEq for Rtti {
98    fn eq(&self, other: &Self) -> bool {
99        self.hash == other.hash && self.variant_hash == other.variant_hash
100    }
101}
102
103impl Eq for Rtti {}
104
105impl hash::Hash for Rtti {
106    fn hash<H: hash::Hasher>(&self, state: &mut H) {
107        self.hash.hash(state);
108        self.variant_hash.hash(state);
109    }
110}
111
112impl PartialOrd for Rtti {
113    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
114        Some(self.cmp(other))
115    }
116}
117
118impl Ord for Rtti {
119    #[inline]
120    fn cmp(&self, other: &Self) -> Ordering {
121        self.hash
122            .cmp(&other.hash)
123            .then_with(|| self.variant_hash.cmp(&other.variant_hash))
124    }
125}