1use super::*;
2
3use crate::{
4 abi_stability::abi_checking::{push_err, AbiInstability},
5 const_utils::log2_usize,
6 std_types::{RSlice, RString, RVec},
7};
8
9#[repr(C)]
13#[derive(Copy, Clone, StableAbi)]
14#[sabi(unsafe_sabi_opaque_fields)]
15pub struct MonoTLEnum {
16 field_count: *const u8,
18 field_count_len: u16,
19
20 variant_names: StartLen,
22
23 pub(super) fields: CompTLFields,
25}
26
27unsafe impl Sync for MonoTLEnum {}
28unsafe impl Send for MonoTLEnum {}
29
30impl MonoTLEnum {
31 pub const fn new(
33 variant_names: StartLen,
34 field_count: RSlice<'static, u8>,
35 fields: CompTLFields,
36 ) -> Self {
37 Self {
38 field_count: field_count.as_ptr(),
39 field_count_len: field_count.len() as u16,
40 variant_names,
41 fields,
42 }
43 }
44
45 pub const fn variant_count(&self) -> usize {
47 self.field_count_len as usize
48 }
49
50 pub const fn field_count(&self) -> RSlice<'static, u8> {
52 unsafe { RSlice::from_raw_parts(self.field_count, self.field_count_len as usize) }
53 }
54
55 pub fn expand(self, other: GenericTLEnum, shared_vars: &'static SharedVars) -> TLEnum {
57 TLEnum {
58 field_count: self.field_count(),
59 variant_names: (&shared_vars.strings()[self.variant_names.to_range()]).into(),
60 fields: self.fields.expand(shared_vars),
61 exhaustiveness: other.exhaustiveness,
62 discriminants: other.discriminants,
63 }
64 }
65}
66
67#[repr(C)]
71#[derive(Debug, Copy, Clone, StableAbi)]
72#[sabi(unsafe_sabi_opaque_fields)]
73pub struct GenericTLEnum {
74 exhaustiveness: IsExhaustive,
76 discriminants: TLDiscriminants,
78}
79
80impl GenericTLEnum {
81 pub const fn new(exhaustiveness: IsExhaustive, discriminants: TLDiscriminants) -> Self {
83 Self {
84 exhaustiveness,
85 discriminants,
86 }
87 }
88
89 pub const fn exhaustive(discriminants: TLDiscriminants) -> Self {
91 Self::new(IsExhaustive::exhaustive(), discriminants)
92 }
93}
94
95#[derive(Debug, Copy, Clone, PartialEq, Eq)]
99pub struct TLEnum {
100 pub field_count: RSlice<'static, u8>,
102
103 pub variant_names: RStr<'static>,
105
106 pub fields: TLFields,
108
109 pub exhaustiveness: IsExhaustive,
111
112 pub discriminants: TLDiscriminants,
114}
115
116impl TLEnum {
117 pub const fn variant_count(&self) -> usize {
119 self.field_count.len()
120 }
121 pub fn variant_names_iter(
123 &self,
124 ) -> impl ExactSizeIterator<Item = &'static str> + Clone + Debug + 'static {
125 GetVariantNames {
126 split: self.variant_names.as_str().split(';'),
127 length: self.field_count.len(),
128 current: 0,
129 }
130 }
131
132 pub const fn max_min<'a>(&'a self, other: &'a TLEnum) -> (&'a TLEnum, &'a TLEnum) {
135 if self.variant_count() < other.variant_count() {
136 (self, other)
137 } else {
138 (other, self)
139 }
140 }
141}
142
143impl Display for TLEnum {
144 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
145 writeln!(f, "variants:{:?}", self.variant_names)?;
146 writeln!(
147 f,
148 "fields(all variants combined):\n{}",
149 self.fields.to_string().left_padder(4)
150 )?;
151 writeln!(f, "field counts(per-variant):{:?}", self.field_count)?;
152 writeln!(f, "exhaustiveness:{:?}", self.exhaustiveness)?;
153 writeln!(f, "discriminants:{:?}", self.discriminants)?;
154 Ok(())
155 }
156}
157
158macro_rules! declare_tl_discriminants {
161 (
162 $((
163 $(#[$variant_attr:meta])*
164 $variant:ident ( $ty:ty ),
165 $single:ident,
166 $(#[$method_attr:meta])*
167 $method:ident
168 ))*
169 ) => (
170 #[repr(C)]
172 #[derive(Copy, Clone, StableAbi)]
173 pub struct TLDiscriminants{
174 inner:TLDiscrsInner,
175 }
176
177 unsafe impl Sync for TLDiscriminants {}
178 unsafe impl Send for TLDiscriminants {}
179
180 #[repr(u8)]
181 #[derive(Copy, Clone, StableAbi)]
182 enum TLDiscrsInner{
183 $(
184 $(#[$variant_attr])*
185 $variant{
188 len:u16,
189 discriminants:*const $ty,
190 },
191 )*
192 }
193
194 impl Debug for TLDiscriminants{
195 fn fmt(&self,f:&mut fmt::Formatter<'_>)->fmt::Result{
196 match self.inner {
197 $(
198 TLDiscrsInner::$variant{discriminants,len}=>unsafe{
199 let slice=std::slice::from_raw_parts(discriminants,len as usize);
200 Debug::fmt(slice,f)
201 }
202 )*
203 }
204 }
205 }
206
207 impl PartialEq for TLDiscriminants {
208 fn eq(&self,other:&Self)->bool{
209 match (self.inner,other.inner) {
210 $(
211 (
212 TLDiscrsInner::$variant{discriminants: t_discr_ptr, len:t_len },
213 TLDiscrsInner::$variant{discriminants: o_discr_ptr, len:o_len }
214 )=>{
215 let t_discrs=unsafe{
216 RSlice::from_raw_parts(t_discr_ptr,t_len as usize)
217 };
218 let o_discrs=unsafe{
219 RSlice::from_raw_parts(o_discr_ptr,o_len as usize)
220 };
221 t_discrs==o_discrs
222 }
223 )*
224 _=>false,
225 }
226 }
227 }
228
229 impl Eq for TLDiscriminants{}
230
231 impl TLDiscriminants{
232
233 $(
234 $(#[$method_attr])*
235 pub const fn $method(arr:RSlice<'static,$ty>)->Self{
236 let inner=TLDiscrsInner::$variant{
237 len:arr.len() as u16,
238 discriminants:arr.as_ptr(),
239 };
240 TLDiscriminants{inner}
241 }
242 )*
243
244 pub const fn discriminant_repr(&self)->DiscriminantRepr{
246 match self.inner {
247 $(
248 TLDiscrsInner::$variant{..}=>DiscriminantRepr::$variant,
249 )*
250 }
251 }
252
253 pub fn compare(&self,other:&Self)->Result<(),RVec<AbiInstability>>{
264 let mut errs=RVec::new();
265 match (self.inner,other.inner) {
266 $(
267 (
268 TLDiscrsInner::$variant{discriminants: t_discr_ptr, len:t_len },
269 TLDiscrsInner::$variant{discriminants: o_discr_ptr, len:o_len }
270 )=>{
271 let t_discrs=unsafe{
272 RSlice::from_raw_parts(t_discr_ptr,t_len as usize)
273 };
274 let o_discrs=unsafe{
275 RSlice::from_raw_parts(o_discr_ptr,o_len as usize)
276 };
277
278 for (&t_discr,&o_discr) in
279 t_discrs.as_slice().iter().zip(o_discrs.as_slice())
280 {
281 if t_discr!=o_discr {
282 push_err(
283 &mut errs,
284 t_discr,
285 o_discr,
286 |x| TLDiscriminant::$single(x as _),
287 AbiInstability::EnumDiscriminant,
288 );
289 }
290 }
291 }
292 )*
293 _=>{
294 push_err(
295 &mut errs,
296 self,
297 other,
298 |x| ReprAttr::Int(x.discriminant_repr()),
299 AbiInstability::ReprAttr
300 );
301 }
302 }
303 if errs.is_empty(){
304 Ok(())
305 }else{
306 Err(errs)
307 }
308 }
309 }
310 )
311}
312
313declare_tl_discriminants! {
314 (
315 U8(u8) ,
316 Signed ,
317 from_u8_slice
319 )
320 (
321 I8(i8) ,
322 Unsigned,
323 from_i8_slice
325 )
326 (
327 U16(u16) ,
328 Signed ,
329 from_u16_slice
331 )
332 (
333 I16(i16) ,
334 Unsigned,
335 from_i16_slice
337 )
338 (
339 U32(u32) ,
340 Signed ,
341 from_u32_slice
343 )
344 (
345 I32(i32) ,
346 Unsigned,
347 from_i32_slice
349 )
350 (
351 U64(u64) ,
352 Signed ,
353 from_u64_slice
355 )
356 (
357 I64(i64) ,
358 Unsigned,
359 from_i64_slice
361 )
362 (
363 Usize(usize) ,
364 Usize,
365 from_usize_slice
367 )
368 (
369 Isize(isize) ,
370 Isize,
371 from_isize_slice
373 )
374}
375
376#[repr(u8)]
378#[derive(Debug, Copy, Clone, PartialEq, Eq, StableAbi)]
379#[sabi(unsafe_sabi_opaque_fields)]
380pub enum TLDiscriminant {
381 Isize(isize),
383 Usize(usize),
385 Signed(i64),
387 Unsigned(u64),
389}
390
391#[repr(u8)]
393#[derive(Debug, Copy, Clone, PartialEq, Eq, StableAbi)]
394#[sabi(unsafe_sabi_opaque_fields)]
395pub enum DiscriminantRepr {
396 U8,
398 I8,
400 U16,
402 I16,
404 U32,
406 I32,
408 U64,
410 I64,
412 U128,
414 I128,
416 Usize,
418 Isize,
422}
423
424#[repr(transparent)]
426#[derive(Debug, Copy, Clone, PartialEq, Eq, StableAbi)]
427#[sabi(unsafe_sabi_opaque_fields)]
428pub struct IsExhaustive {
429 value: Option<&'static TLNonExhaustive>,
430}
431
432impl IsExhaustive {
433 pub const fn exhaustive() -> IsExhaustive {
435 IsExhaustive { value: None }
436 }
437 pub const fn nonexhaustive(nonexhaustive: &'static TLNonExhaustive) -> IsExhaustive {
439 IsExhaustive {
440 value: Some(nonexhaustive),
441 }
442 }
443 pub const fn is_exhaustive(&self) -> bool {
445 self.value.is_none()
446 }
447 pub const fn is_nonexhaustive(&self) -> bool {
449 self.value.is_some()
450 }
451 pub const fn as_nonexhaustive(&self) -> Option<&'static TLNonExhaustive> {
453 self.value
454 }
455}
456
457#[repr(C)]
459#[derive(Debug, Copy, Clone, PartialEq, Eq, StableAbi)]
460#[sabi(unsafe_sabi_opaque_fields)]
461pub struct TLNonExhaustive {
462 original_size: usize,
463 original_alignment_pow2: u8,
464}
465
466impl TLNonExhaustive {
467 pub const fn new<T>() -> Self {
469 Self {
470 original_size: std::mem::size_of::<T>(),
471 original_alignment_pow2: log2_usize(mem::align_of::<T>()),
472 }
473 }
474
475 #[inline]
476 const fn original_size(&self) -> usize {
477 self.original_size
478 }
479 #[inline]
480 const fn original_alignment(&self) -> usize {
481 1_usize << (self.original_alignment_pow2 as u32)
482 }
483
484 pub fn check_compatible(
487 &self,
488 layout: &TypeLayout,
489 ) -> Result<(), IncompatibleWithNonExhaustive> {
490 let err =
491 layout.size() < self.original_size() || layout.alignment() < self.original_alignment();
492
493 if err {
494 Err(IncompatibleWithNonExhaustive {
495 full_type: layout.full_type().to_string().into(),
496 module_path: layout.mod_path(),
497 type_size: self.original_size(),
498 type_alignment: self.original_alignment(),
499 storage_size: layout.size(),
500 storage_alignment: layout.alignment(),
501 })
502 } else {
503 Ok(())
504 }
505 }
506}
507
508#[doc(hidden)]
509pub struct MakeTLNonExhaustive<T>(T);
510
511impl<T> MakeTLNonExhaustive<T> {
512 pub const NEW: TLNonExhaustive = TLNonExhaustive::new::<T>();
513}
514
515#[repr(C)]
520#[derive(Debug, Clone, PartialEq, Eq, StableAbi)]
521#[sabi(unsafe_sabi_opaque_fields)]
522pub struct IncompatibleWithNonExhaustive {
523 full_type: RString,
524 module_path: ModPath,
525 type_size: usize,
526 type_alignment: usize,
527 storage_size: usize,
528 storage_alignment: usize,
529}
530
531impl Display for IncompatibleWithNonExhaustive {
532 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
533 write!(
534 f,
535 "Type '{ty}' has an incompatible layout for the storage.\n\
536 Type size:{t_size} alignment:{t_align}
537 Storage size:{s_size} alignment:{s_align}
538 module_path:{mod_}
539 ",
540 ty = self.full_type,
541 t_size = self.type_size,
542 t_align = self.type_alignment,
543 s_size = self.storage_size,
544 s_align = self.storage_alignment,
545 mod_ = self.module_path,
546 )
547 }
548}
549
550impl std::error::Error for IncompatibleWithNonExhaustive {}
551
552#[derive(Debug, Clone)]
556struct GetVariantNames {
557 split: std::str::Split<'static, char>,
558 length: usize,
559 current: usize,
560}
561
562impl Iterator for GetVariantNames {
563 type Item = &'static str;
564 fn next(&mut self) -> Option<Self::Item> {
565 if self.length == self.current {
566 return None;
567 }
568 let current = self.current;
569 self.current += 1;
570 match self.split.next().filter(|&x| !x.is_empty() || x == "_") {
571 Some(x) => Some(x),
572 None => Some(VARIANT_INDEX[current]),
573 }
574 }
575
576 fn size_hint(&self) -> (usize, Option<usize>) {
577 let len = self.length - self.current;
578 (len, Some(len))
579 }
580 fn count(self) -> usize {
581 self.length - self.current
582 }
583}
584
585impl std::iter::ExactSizeIterator for GetVariantNames {}
586
587static VARIANT_INDEX: [&str; 68] = [
588 "Variant0",
589 "Variant1",
590 "Variant2",
591 "Variant3",
592 "Variant4",
593 "Variant5",
594 "Variant6",
595 "Variant7",
596 "Variant8",
597 "Variant9",
598 "Variant10",
599 "Variant11",
600 "Variant12",
601 "Variant13",
602 "Variant14",
603 "Variant15",
604 "Variant16",
605 "Variant17",
606 "Variant18",
607 "Variant19",
608 "Variant20",
609 "Variant21",
610 "Variant22",
611 "Variant23",
612 "Variant24",
613 "Variant25",
614 "Variant26",
615 "Variant27",
616 "Variant28",
617 "Variant29",
618 "Variant30",
619 "Variant31",
620 "Variant32",
621 "Variant33",
622 "Variant34",
623 "Variant35",
624 "Variant36",
625 "Variant37",
626 "Variant38",
627 "Variant39",
628 "Variant40",
629 "Variant41",
630 "Variant42",
631 "Variant43",
632 "Variant44",
633 "Variant45",
634 "Variant46",
635 "Variant47",
636 "Variant48",
637 "Variant49",
638 "Variant50",
639 "Variant51",
640 "Variant52",
641 "Variant53",
642 "Variant54",
643 "Variant55",
644 "Variant56",
645 "Variant57",
646 "Variant58",
647 "Variant59",
648 "Variant60",
649 "Variant61",
650 "Variant62",
651 "Variant63",
652 "Variant64",
653 "Variant65",
654 "Variant66",
655 "Variant67",
656];