1#![no_std]
2
3extern crate alloc;
4
5pub use sails_idl_ast::InterfaceId;
6use sails_type_registry::{MetaType, TypeInfo};
7
8mod header;
9pub use header::*;
10
11pub trait Identifiable {
13 const INTERFACE_ID: InterfaceId;
14}
15
16pub trait MethodMeta: Identifiable {
18 const ENTRY_ID: u16;
19}
20
21#[derive(Debug, Clone)]
22pub struct BaseServiceMeta {
23 pub name: &'static str,
24 pub interface_id: InterfaceId,
25 pub meta: AnyServiceMeta,
26 pub base: &'static [BaseServiceMeta],
27}
28
29impl BaseServiceMeta {
30 pub const fn new<S: ServiceMeta + ?Sized>(name: &'static str) -> Self {
31 Self {
32 name,
33 interface_id: S::INTERFACE_ID,
34 meta: S::META,
35 base: S::BASE_SERVICES,
36 }
37 }
38}
39
40#[derive(Debug)]
42pub struct MethodMetadata {
43 pub name: &'static str,
44 pub entry_id: u16,
45 pub hash: [u8; 32],
46 pub is_async: bool,
47}
48
49pub trait ServiceMeta: Identifiable {
50 type CommandsMeta: TypeInfo;
51 type QueriesMeta: TypeInfo;
52 type EventsMeta: TypeInfo;
53 const BASE_SERVICES: &'static [BaseServiceMeta];
55 const METHODS: &'static [MethodMetadata];
58 const ASYNC: bool;
59 const META: AnyServiceMeta = AnyServiceMeta::new::<Self>();
60}
61
62#[derive(Debug, Clone)]
63pub struct AnyServiceMeta {
64 commands: MetaType,
65 queries: MetaType,
66 events: MetaType,
67 base_services: &'static [BaseServiceMeta],
68 interface_id: InterfaceId,
69}
70
71impl AnyServiceMeta {
72 pub const fn new<S: ServiceMeta + ?Sized>() -> Self {
73 Self {
74 commands: S::CommandsMeta::META,
75 queries: S::QueriesMeta::META,
76 events: S::EventsMeta::META,
77 base_services: S::BASE_SERVICES,
78 interface_id: S::INTERFACE_ID,
79 }
80 }
81
82 pub fn commands(&self) -> &MetaType {
83 &self.commands
84 }
85
86 pub fn queries(&self) -> &MetaType {
87 &self.queries
88 }
89
90 pub fn events(&self) -> &MetaType {
91 &self.events
92 }
93
94 pub fn base_services(&self) -> impl Iterator<Item = (&'static str, AnyServiceMeta)> {
95 self.base_services
96 .iter()
97 .map(|base| (base.name, base.meta.clone()))
98 }
99
100 pub fn interface_id(&self) -> InterfaceId {
101 self.interface_id
102 }
103}
104
105pub trait ProgramMeta {
106 type ConstructorsMeta: TypeInfo;
107 const SERVICES: &'static [(&'static str, AnyServiceMeta)];
108 const ASYNC: bool;
109}
110
111pub const fn count_base_services<S: ServiceMeta>() -> usize {
112 let mut counter = 0;
113
114 let direct_base_services = S::BASE_SERVICES;
115 let mut idx = 0;
116 while idx != direct_base_services.len() {
117 let base = &direct_base_services[idx];
118 count_base_services_recursive(&mut counter, base);
119 idx += 1;
120 }
121
122 counter
123}
124
125const fn count_base_services_recursive(counter: &mut usize, base: &BaseServiceMeta) {
126 *counter += 1;
127
128 let base_services = base.base;
129 let mut idx = 0;
130 while idx != base_services.len() {
131 count_base_services_recursive(counter, &base_services[idx]);
132 idx += 1;
133 }
134}
135
136pub const fn interface_ids<const N: usize>(
138 exposed_services: &'static [BaseServiceMeta],
139) -> [(InterfaceId, u8); N] {
140 let mut output = [(InterfaceId([0u8; 8]), 0u8); N];
141
142 let mut exposed_svc_idx = 0;
143 let mut output_offset = 0;
144 let mut route_id = 1;
145 while exposed_svc_idx != exposed_services.len() {
146 let service = &exposed_services[exposed_svc_idx];
147 fill_interface_ids_recursive(&mut output, &mut output_offset, service, route_id);
148 exposed_svc_idx += 1;
149 route_id += 1;
150 }
151
152 assert!(output_offset == N, "Mismatched interface IDs count");
153
154 output
155}
156
157const fn fill_interface_ids_recursive(
158 arr: &mut [(InterfaceId, u8)],
159 offset: &mut usize,
160 service: &BaseServiceMeta,
161 route_id: u8,
162) {
163 arr[*offset] = (service.interface_id, route_id);
164 *offset += 1;
165 let base_services = service.base;
166 let mut idx = 0;
167 while idx != base_services.len() {
168 fill_interface_ids_recursive(arr, offset, &base_services[idx], route_id);
169 idx += 1;
170 }
171}
172
173pub const fn service_has_interface_id(
174 service: &BaseServiceMeta,
175 interface_id: InterfaceId,
176) -> bool {
177 if service.interface_id.as_u64() == interface_id.as_u64() {
178 true
179 } else {
180 let mut idx = 0;
181 while idx != service.base.len() {
182 if service_has_interface_id(&service.base[idx], interface_id) {
183 return true;
184 }
185 idx += 1;
186 }
187 false
188 }
189}
190
191pub const fn str_eq(a: &str, b: &str) -> bool {
192 let a_bytes = a.as_bytes();
193 let b_bytes = b.as_bytes();
194 if a_bytes.len() != b_bytes.len() {
195 return false;
196 }
197 let mut i = 0;
198 while i < a_bytes.len() {
199 if a_bytes[i] != b_bytes[i] {
200 return false;
201 }
202 i += 1;
203 }
204 true
205}
206
207pub const fn bytes32_eq(a: &[u8; 32], b: &[u8; 32]) -> bool {
208 let mut i = 0;
209 while i < 32 {
210 if a[i] != b[i] {
211 return false;
212 }
213 i += 1;
214 }
215 true
216}
217
218pub const fn find_method_data(
219 methods: &'static [MethodMetadata],
220 name: &str,
221 entry_id: Option<u16>,
222) -> Option<&'static MethodMetadata> {
223 if let Some(id) = entry_id {
224 let i = id as usize;
225 if i < methods.len() {
226 return Some(&methods[i]);
227 }
228 return None;
229 }
230 let mut i = 0;
231 while i < methods.len() {
232 let m = &methods[i];
233 if str_eq(m.name, name) {
234 return Some(m);
235 }
236 i += 1;
237 }
238 None
239}
240
241pub const fn find_id(methods: &'static [MethodMetadata], name: &str) -> u16 {
242 let mut i = 0;
243 while i < methods.len() {
244 if str_eq(methods[i].name, name) {
245 return methods[i].entry_id;
246 }
247 i += 1;
248 }
249 0
250}