Skip to main content

wasefire_wire/
internal.rs

1// Copyright 2024 Google LLC
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15//! Internal details exposed for the derive macro.
16
17pub use alloc::vec::Vec;
18
19use wasefire_error::{Code, Error, Space};
20
21#[cfg(feature = "schema")]
22pub use self::schema::*;
23pub use crate::reader::Reader;
24pub use crate::writer::Writer;
25
26pub type Result<T> = core::result::Result<T, Error>;
27
28pub trait Wire<'a>: 'a + Sized {
29    type Type<'b>: 'b + Sized + Wire<'b>; // Type<'a> == Self
30    #[cfg(feature = "schema")]
31    fn schema(rules: &mut Rules);
32    fn encode(&self, writer: &mut Writer<'a>) -> Result<()>;
33    fn decode(reader: &mut Reader<'a>) -> Result<Self>;
34}
35
36pub const INVALID_TAG: Error = Error::new_const(Space::User as u8, Code::InvalidArgument as u16);
37
38pub fn encode_tag(tag: u32, writer: &mut Writer) -> Result<()> {
39    <u32 as crate::internal::Wire>::encode(&tag, writer)
40}
41
42pub fn decode_tag(reader: &mut Reader) -> Result<u32> {
43    <u32 as crate::internal::Wire>::decode(reader)
44}
45
46#[cfg(feature = "schema")]
47mod schema {
48    use alloc::vec::Vec;
49    use core::any::TypeId;
50    use std::collections::HashMap;
51    use std::collections::hash_map::Entry;
52
53    use crate::Wire;
54
55    pub fn schema<'a, T: Wire<'a>>(rules: &mut Rules) {
56        T::schema(rules)
57    }
58
59    pub fn type_id<'a, T: Wire<'a>>() -> TypeId {
60        TypeId::of::<T::Type<'static>>()
61    }
62
63    #[derive(Debug, Copy, Clone, PartialEq, Eq, wasefire_wire_derive::Wire)]
64    #[wire(crate = crate, range = 11)]
65    pub enum Builtin {
66        Bool,
67        U8,
68        I8,
69        U16,
70        I16,
71        U32,
72        I32,
73        U64,
74        I64,
75        Usize,
76        Isize,
77    }
78
79    #[derive(Debug, Default)]
80    pub struct Rules(HashMap<TypeId, Rule>);
81
82    #[derive(Debug, Clone, PartialEq, Eq)]
83    pub enum Rule {
84        Builtin(Builtin),
85        Alias(TypeId),
86        Array(TypeId, usize),
87        Slice(TypeId),
88        Struct(RuleStruct),
89        Enum(RuleEnum),
90    }
91    pub type RuleStruct = Vec<(Option<&'static str>, TypeId)>;
92    pub type RuleEnum = Vec<(&'static str, u32, RuleStruct)>;
93
94    impl Rules {
95        pub(crate) fn builtin<X: 'static>(&mut self, builtin: Builtin) {
96            let _ = self.insert::<X>(Rule::Builtin(builtin));
97        }
98
99        pub fn alias<X: 'static, T: Wire<'static>>(&mut self) {
100            if self.insert::<X>(Rule::Alias(TypeId::of::<T>())) {
101                T::schema(self);
102            }
103        }
104
105        pub(crate) fn array<X: 'static, T: Wire<'static>>(&mut self, n: usize) {
106            if self.insert::<X>(Rule::Array(TypeId::of::<T>(), n)) {
107                T::schema(self);
108            }
109        }
110
111        pub(crate) fn slice<X: 'static, T: Wire<'static>>(&mut self) {
112            if self.insert::<X>(Rule::Slice(TypeId::of::<T>())) {
113                T::schema(self);
114            }
115        }
116
117        pub fn struct_<X: 'static>(&mut self, fields: RuleStruct) -> bool {
118            self.insert::<X>(Rule::Struct(fields))
119        }
120
121        pub fn enum_<X: 'static>(&mut self, variants: RuleEnum) -> bool {
122            self.insert::<X>(Rule::Enum(variants))
123        }
124
125        fn insert<T: 'static>(&mut self, rule: Rule) -> bool {
126            match self.0.entry(TypeId::of::<T>()) {
127                Entry::Occupied(old) => {
128                    assert_eq!(old.get(), &rule);
129                    false
130                }
131                Entry::Vacant(x) => {
132                    let _ = x.insert(rule);
133                    true
134                }
135            }
136        }
137
138        pub(crate) fn get(&self, mut id: TypeId) -> &Rule {
139            for _ in 0 .. 40 {
140                match self.0.get(&id).unwrap() {
141                    Rule::Alias(x) => id = *x,
142                    x => return x,
143                }
144            }
145            panic!("possible alias cycle in schema rules");
146        }
147    }
148}