rune/runtime/value/
rtti.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
use core::borrow::Borrow;
use core::cmp::Ordering;
use core::hash;

use rust_alloc::sync::Arc;

use serde::{Deserialize, Serialize};

use crate::alloc::prelude::*;
use crate::alloc::HashMap;
use crate::item::Item;
use crate::runtime::{FieldMap, TypeInfo, Value};
use crate::{Hash, ItemBuf};

/// Field accessor for a variant struct.
#[doc(hidden)]
pub struct Accessor<'a> {
    pub(crate) fields: &'a HashMap<Box<str>, usize>,
    pub(crate) data: &'a [Value],
}

impl Accessor<'_> {
    /// Get a field through the accessor.
    #[doc(hidden)]
    pub fn get<Q>(&self, key: &Q) -> Option<&Value>
    where
        Box<str>: Borrow<Q>,
        Q: hash::Hash + Eq + ?Sized,
    {
        self.data.get(*self.fields.get(key)?)
    }
}

/// The kind of value stored.
#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
#[serde(rename_all = "kebab-case")]
pub(crate) enum RttiKind {
    /// The value stored is empty.
    Empty,
    /// The value stored is a tuple.
    Tuple,
    /// The value stored is a strict.
    Struct,
}

/// Runtime information on variant.
#[derive(Debug, Serialize, Deserialize)]
#[non_exhaustive]
pub struct Rtti {
    /// The kind of value.
    pub(crate) kind: RttiKind,
    /// The type hash of the type.
    pub(crate) hash: Hash,
    /// If this type is a variant, designates the hash of the variant.
    pub(crate) variant_hash: Hash,
    /// The item of the type.
    pub(crate) item: ItemBuf,
    /// Mapping from field names to their corresponding indexes.
    pub(crate) fields: FieldMap<Box<str>, usize>,
}

impl Rtti {
    /// Test if this RTTI matches the given raw hashes.
    #[inline]
    pub(crate) fn is(&self, hash: Hash, variant_hash: Hash) -> bool {
        self.hash == hash && self.variant_hash == variant_hash
    }

    /// Access the item of the RTTI.
    #[inline]
    pub fn item(&self) -> &Item {
        &self.item
    }

    /// Access the type hash of the RTTI.
    #[inline]
    pub fn type_hash(&self) -> Hash {
        self.hash
    }

    /// Access the type information for the RTTI.
    #[inline]
    pub fn type_info(self: Arc<Self>) -> TypeInfo {
        TypeInfo::rtti(self)
    }
}

impl PartialEq for Rtti {
    fn eq(&self, other: &Self) -> bool {
        self.hash == other.hash && self.variant_hash == other.variant_hash
    }
}

impl Eq for Rtti {}

impl hash::Hash for Rtti {
    fn hash<H: hash::Hasher>(&self, state: &mut H) {
        self.hash.hash(state);
        self.variant_hash.hash(state);
    }
}

impl PartialOrd for Rtti {
    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
        Some(self.cmp(other))
    }
}

impl Ord for Rtti {
    #[inline]
    fn cmp(&self, other: &Self) -> Ordering {
        self.hash
            .cmp(&other.hash)
            .then_with(|| self.variant_hash.cmp(&other.variant_hash))
    }
}