schema_emit_runtime/
lib.rs1#![doc = include_str!("../README.md")]
2#![no_std]
3
4#[cfg(feature = "decode")]
5extern crate std;
6
7#[cfg(feature = "decode")]
8pub mod decode;
9mod place;
10
11pub use pattern_emit::{Pattern, Unusable};
12pub use place::{under, Trail};
13
14#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)]
16pub enum Reason {
17 Absent,
19 Range,
22 Duplicate,
24 Cast,
27}
28
29impl Reason {
30 pub const fn name(self) -> &'static str {
32 match self {
33 Reason::Absent => "absent",
34 Reason::Range => "range",
35 Reason::Duplicate => "duplicate",
36 Reason::Cast => "cast",
37 }
38 }
39}
40
41pub trait Report {
55 fn fail(&mut self, path: &'static str, at: &[u32], reason: Reason);
56}
57
58#[derive(Clone, Copy, Debug, PartialEq, Eq)]
60pub struct Failure {
61 pub path: &'static str,
62 pub at: [u32; DEPTH],
63 pub reason: Reason,
64}
65
66pub const DEPTH: usize = 4;
68
69#[derive(Clone, Copy, Debug)]
71pub struct Failures<const N: usize> {
72 list: [Option<Failure>; N],
73 len: usize,
74 pub dropped: u32,
75}
76
77impl<const N: usize> Default for Failures<N> {
78 fn default() -> Self {
79 Failures {
80 list: [None; N],
81 len: 0,
82 dropped: 0,
83 }
84 }
85}
86
87impl<const N: usize> Failures<N> {
88 pub fn iter(&self) -> impl Iterator<Item = &Failure> {
90 self.list.iter().flatten()
91 }
92
93 pub fn is_empty(&self) -> bool {
94 self.len == 0 && self.dropped == 0
95 }
96
97 pub fn len(&self) -> usize {
98 self.len
99 }
100}
101
102impl<const N: usize> Report for Failures<N> {
103 fn fail(&mut self, path: &'static str, at: &[u32], reason: Reason) {
104 let mut kept = [0; DEPTH];
105 for (k, a) in kept.iter_mut().zip(at) {
106 *k = *a;
107 }
108 match self.list.get_mut(self.len) {
109 Some(slot) => {
110 *slot = Some(Failure {
111 path,
112 at: kept,
113 reason,
114 });
115 self.len = self.len.saturating_add(1);
116 }
117 None => self.dropped = self.dropped.saturating_add(1),
118 }
119 }
120}
121
122#[derive(Clone, Copy, Debug, Default)]
125pub struct Holds {
126 failed: bool,
127}
128
129impl Holds {
130 pub fn held(&self) -> bool {
131 !self.failed
132 }
133}
134
135impl Report for Holds {
136 fn fail(&mut self, _: &'static str, _: &[u32], _: Reason) {
137 self.failed = true;
138 }
139}
140
141#[derive(Clone, Copy, Debug)]
143pub struct Under {
144 path: &'static str,
145 pub reason: Option<Reason>,
146}
147
148impl Under {
149 pub const fn new(path: &'static str) -> Under {
150 Under { path, reason: None }
151 }
152}
153
154impl Report for Under {
155 fn fail(&mut self, path: &'static str, at: &[u32], reason: Reason) {
156 if self.reason.is_none() && under(self.path, path, at) {
157 self.reason = Some(reason);
158 }
159 }
160}
161
162pub fn multiple_of(x: f64, m: f64) -> bool {
165 let q = x / m;
166 q.is_finite() && q == trunc(q)
167}
168
169fn trunc(x: f64) -> f64 {
171 const WHOLE: f64 = 4_503_599_627_370_496.0;
172 if x.is_nan() || x.abs() >= WHOLE {
173 return x;
174 }
175 #[allow(clippy::cast_possible_truncation)]
177 let t = x as i64;
178 t as f64
179}
180
181pub fn chars(s: &str) -> u64 {
183 s.chars().fold(0u64, |n, _| n.saturating_add(1))
184}
185
186#[cfg(test)]
187mod tests;