1use alloc::borrow::Cow;
15use alloc::boxed::Box;
16use alloc::collections::BTreeMap;
17use alloc::string::ToString;
18use alloc::sync::Arc;
19use alloc::vec::Vec;
20use core::any::{Any, TypeId, type_name};
21use core::fmt;
22use core::marker::PhantomData;
23
24use crate::State;
25use crate::Text;
26use crate::de::enums::{
27 AdjacentlyTaggedSink, ArenaVariant, EnumKey, ExternallyTaggedSink, InternallyTaggedSink, Tag,
28 UntaggedTry, ValueVariant, VariantBuilder, VariantNames, Variants, no_matching_variant,
29 untagged_handle_with,
30};
31use crate::de::mapped::mapped;
32use crate::de::{Deserialize, DeserializeOwned, OwnedSink, Sink, SinkHandle};
33use crate::error::{Error, ErrorKind};
34use crate::event::{Atom, ContainerShape};
35use crate::ser::enums::{EntrySer, FieldsSer, TaggedNewtype};
36use crate::ser::{
37 Describe, Emit, Serialize, SerializeHandle, SerializeRef, Variant, VariantKind, VariantRepr,
38};
39
40pub trait OpenEnum: Send + Sync + 'static {
47 #[doc(hidden)]
49 const INFO: &'static OpenEnumInfo;
50
51 #[doc(hidden)]
53 fn __private_variant(value: &Self) -> VariantValue<'_>;
54}
55
56pub trait OpenVariant<O: ?Sized + OpenEnum>: Serialize + DeserializeOwned + 'static {
62 #[doc(hidden)]
64 const ENTRY: &'static VariantEntry;
65
66 #[doc(hidden)]
72 fn __private_into_box(self) -> Box<O>;
73}
74
75type MakeVariant<O> =
80 for<'a, 'de> fn(&mut State, PhantomData<&'a &'de ()>) -> ArenaVariant<'a, 'de, Box<O>>;
81
82fn make_variant<'a, 'de, O: ?Sized + OpenEnum, T: OpenVariant<O>>(
84 state: &mut State,
85 _: PhantomData<&'a &'de ()>,
86) -> ArenaVariant<'a, 'de, Box<O>> {
87 ValueVariant::arena(T::__private_into_box, state)
88}
89
90type TryVariant<O> = for<'t, 'de> fn(&mut UntaggedTry<'t, 'de, Box<O>>);
92
93fn try_variant<O: ?Sized + OpenEnum, T: OpenVariant<O>>(attempt: &mut UntaggedTry<'_, '_, Box<O>>) {
95 attempt.variant::<T>(T::__private_into_box);
96}
97
98const STYLES: usize = 8;
100
101#[doc(hidden)]
104pub struct VariantEntry {
105 pub styled: &'static [&'static str; STYLES],
110 pub rename: Option<Tag<'static>>,
112 pub aliases: &'static [Tag<'static>],
114}
115
116#[doc(hidden)]
118#[derive(Clone, Copy)]
119pub enum OpenRepr {
120 External,
122 Internal {
124 tag: EnumKey,
126 },
127 Adjacent {
129 tag: EnumKey,
131 content: EnumKey,
133 deny_unknown_fields: bool,
135 },
136 Untagged,
139}
140
141#[doc(hidden)]
143pub struct OpenEnumInfo {
144 pub name: &'static str,
146 pub repr: OpenRepr,
148 pub rename_all: usize,
151 pub alias_all: &'static [usize],
154}
155
156#[doc(hidden)]
161pub struct VariantValue<'a> {
162 entry: &'static VariantEntry,
163 content: SerializeRef<'a>,
164}
165
166impl<'a> VariantValue<'a> {
167 #[inline]
169 pub fn new<T: Serialize>(entry: &'static VariantEntry, value: &'a T) -> VariantValue<'a> {
170 VariantValue {
171 entry,
172 content: SerializeRef::new(value),
173 }
174 }
175}
176
177impl VariantEntry {
180 #[inline]
182 fn name(&'static self, info: &OpenEnumInfo) -> Tag<'static> {
183 match self.rename {
184 Some(name) => name,
185 None => Tag::Str(self.styled[info.rename_all]),
186 }
187 }
188
189 #[inline]
193 fn name_handle(&'static self, info: &OpenEnumInfo) -> SerializeHandle<'static> {
194 match self.rename {
195 Some(Tag::Str(ref name)) => SerializeHandle::to(name),
196 Some(ref name) => SerializeHandle::to(name),
197 None => SerializeHandle::to(&self.styled[info.rename_all]),
198 }
199 }
200
201 #[inline]
203 fn name_str(&'static self, info: &OpenEnumInfo) -> Option<&'static str> {
204 match self.name(info) {
205 Tag::Str(name) => Some(name),
206 _ => None,
207 }
208 }
209
210 fn tags(&'static self, info: &OpenEnumInfo) -> Vec<Tag<'static>> {
212 let name = self.name(info);
213 let mut tags = Vec::from([name]);
214 let mut push = |tag: Tag<'static>| {
215 if !tags.contains(&tag) {
216 tags.push(tag);
217 }
218 };
219 for &alias in self.aliases {
220 push(alias);
221 }
222 for &style in info.alias_all {
224 push(Tag::Str(self.styled[style]));
225 }
226 tags
227 }
228
229 fn display_name(&self, info: &OpenEnumInfo) -> Cow<'static, str> {
231 match self.rename {
232 Some(tag) => tag_display(tag),
233 None => Cow::Borrowed(self.styled[info.rename_all]),
234 }
235 }
236}
237
238fn tag_display(tag: Tag<'static>) -> Cow<'static, str> {
240 match tag {
241 Tag::Str(name) => Cow::Borrowed(name),
242 Tag::U64(value) => Cow::Owned(value.to_string()),
243 Tag::I64(value) => Cow::Owned(value.to_string()),
244 Tag::Bool(value) => Cow::Borrowed(if value { "true" } else { "false" }),
245 }
246}
247
248#[derive(Default)]
282pub struct OpenEnums {
283 enums: BTreeMap<TypeId, Registered>,
284}
285
286struct Registered {
288 name: &'static str,
290 names: Vec<Cow<'static, str>>,
292 table: Box<dyn Any + Send + Sync>,
294}
295
296struct Table<O: ?Sized + 'static> {
298 variants: Vec<Registration<O>>,
301 tags: Vec<(Tag<'static>, usize)>,
304}
305
306struct Registration<O: ?Sized + 'static> {
308 ty: TypeId,
310 type_name: &'static str,
312 make: MakeVariant<O>,
314 try_untagged: TryVariant<O>,
316}
317
318impl OpenEnums {
319 pub fn new() -> OpenEnums {
321 OpenEnums::default()
322 }
323
324 pub fn register<O: ?Sized + OpenEnum, T: OpenVariant<O>>(
332 &mut self,
333 ) -> Result<&mut OpenEnums, Error> {
334 let entry = T::ENTRY;
335 let info = O::INFO;
336 let ty = TypeId::of::<T>();
337 let registered = self
338 .enums
339 .entry(TypeId::of::<O>())
340 .or_insert_with(|| Registered {
341 name: info.name,
342 names: Vec::new(),
343 table: Box::new(Table::<O> {
344 variants: Vec::new(),
345 tags: Vec::new(),
346 }),
347 });
348 let table = registered
349 .table
350 .downcast_mut::<Table<O>>()
351 .expect("the table of an open enum has the type of the open enum");
352 if table.variants.iter().any(|variant| variant.ty == ty) {
353 return Ok(self);
354 }
355 let tags = match info.repr {
356 OpenRepr::Untagged => Vec::new(),
357 _ => entry.tags(info),
358 };
359 for tag in &tags {
360 if let Ok(index) = table.tags.binary_search_by(|(other, _)| other.cmp(tag)) {
361 return Err(Error::new(
362 ErrorKind::Configuration,
363 alloc::format!(
364 "duplicate variant `{}` of {}: `{}` and `{}`",
365 tag_display(*tag),
366 info.name,
367 table.variants[table.tags[index].1].type_name,
368 type_name::<T>(),
369 ),
370 ));
371 }
372 }
373 let variant = table.variants.len();
374 table.variants.push(Registration {
375 ty,
376 type_name: type_name::<T>(),
377 make: make_variant::<O, T>,
378 try_untagged: try_variant::<O, T>,
379 });
380 for tag in tags {
381 let index = table
382 .tags
383 .binary_search_by(|(other, _)| other.cmp(&tag))
384 .unwrap_err();
385 table.tags.insert(index, (tag, variant));
386 }
387 let name = entry.display_name(info);
388 let index = registered.names.binary_search(&name).unwrap_or_else(|x| x);
389 registered.names.insert(index, name);
390 Ok(self)
391 }
392
393 #[inline]
395 fn get<O: ?Sized + OpenEnum>(&self) -> Option<&Registered> {
396 self.enums.get(&TypeId::of::<O>())
397 }
398
399 #[inline]
401 fn lookup<O: ?Sized + OpenEnum>(&self, tag: Tag<'_>) -> Option<MakeVariant<O>> {
402 let table = self.get::<O>()?.table.downcast_ref::<Table<O>>()?;
403 let index = table
404 .tags
405 .binary_search_by(|(other, _)| other.cmp(&tag))
406 .ok()?;
407 Some(table.variants[table.tags[index].1].make)
408 }
409
410 #[inline]
412 fn untagged<O: ?Sized + OpenEnum>(&self, index: usize) -> Option<TryVariant<O>> {
413 let table = self.get::<O>()?.table.downcast_ref::<Table<O>>()?;
414 Some(table.variants.get(index)?.try_untagged)
415 }
416}
417
418impl fmt::Debug for OpenEnums {
419 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
420 f.debug_map()
421 .entries(
422 self.enums
423 .values()
424 .map(|registered| (registered.name, ®istered.names)),
425 )
426 .finish()
427 }
428}
429
430impl Serialize for Tag<'_> {
431 fn serialize<'a>(value: &'a Self, _state: &mut State) -> Result<Emit<'a>, Error> {
432 Ok(Emit::Atom(match *value {
433 Tag::Str(name) => Atom::Str(Text::borrowed(name)),
434 Tag::U64(value) => Atom::U64(value),
435 Tag::I64(value) => Atom::I64(value),
436 Tag::Bool(value) => Atom::Bool(value),
437 }))
438 }
439}
440
441fn variant_repr(repr: OpenRepr) -> VariantRepr<'static> {
443 match repr {
444 OpenRepr::External => VariantRepr::External,
445 OpenRepr::Internal { tag } => VariantRepr::Internal { tag: tag.name },
446 OpenRepr::Adjacent { tag, content, .. } => VariantRepr::Adjacent {
447 tag: tag.name,
448 content: content.name,
449 },
450 OpenRepr::Untagged => VariantRepr::Untagged,
451 }
452}
453
454pub fn serialize<'a, O: ?Sized + OpenEnum>(
456 value: &'a O,
457 state: &mut State,
458) -> Result<Emit<'a>, Error> {
459 let VariantValue { entry, content } = O::__private_variant(value);
460 let info = O::INFO;
461 Ok(match info.repr {
462 OpenRepr::External => match entry.name_str(info) {
463 Some(name) => {
464 FieldsSer(Vec::from([(name, SerializeHandle::from(content))])).into_emit(state)
465 }
466 None => EntrySer::new(entry.name_handle(info), SerializeHandle::from(content))
467 .into_emit(state),
468 },
469 OpenRepr::Internal { tag } => {
470 TaggedNewtype::new(tag.name, entry.name_handle(info), content).into_emit(state)
471 }
472 OpenRepr::Adjacent {
473 tag,
474 content: content_key,
475 ..
476 } => FieldsSer(Vec::from([
477 (tag.name, entry.name_handle(info)),
478 (content_key.name, SerializeHandle::from(content)),
479 ]))
480 .into_emit(state),
481 OpenRepr::Untagged => Emit::Forward(SerializeHandle::from(content)),
482 })
483}
484
485pub fn describe<O: ?Sized + OpenEnum>(value: &O, d: &mut dyn Describe) {
487 let VariantValue { entry, content } = O::__private_variant(value);
488 let name = entry.display_name(O::INFO);
489 let repr = O::INFO.repr;
490 d.variant(&Variant::new(
491 O::INFO.name,
492 &name,
493 VariantKind::Newtype,
494 variant_repr(repr),
495 ));
496 if let OpenRepr::Internal { .. } | OpenRepr::Untagged = repr {
500 content.describe(d);
501 }
502}
503
504pub fn container_shape<O: ?Sized + OpenEnum>() -> ContainerShape {
506 match O::INFO.repr {
507 OpenRepr::External => ContainerShape::with_len(1),
508 OpenRepr::Internal { .. } => ContainerShape::new(),
509 OpenRepr::Adjacent { .. } => ContainerShape::with_len(2),
510 OpenRepr::Untagged => ContainerShape::new(),
512 }
513}
514
515fn lookup<'a, 'de: 'a, O: ?Sized + OpenEnum>(
517 tag: Tag<'_>,
518 state: &mut State,
519) -> Option<ArenaVariant<'a, 'de, Box<O>>> {
520 let make = match state.get::<OpenEnums>() {
521 Some(registry) if registry.get::<O>().is_some() => registry.lookup::<O>(tag)?,
522 _ => return Some(ArenaVariant::new(Unregistered::<O>::new(), state)),
523 };
524 Some(make(state, PhantomData))
525}
526
527fn untagged_variants<'de, O: ?Sized + OpenEnum>(
531 index: usize,
532 attempt: &mut UntaggedTry<'_, 'de, Box<O>>,
533) -> bool {
534 let try_variant = match attempt.state().get::<OpenEnums>() {
535 Some(registry) => registry.untagged::<O>(index),
536 None => None,
537 };
538 match try_variant {
539 Some(try_variant) => {
540 try_variant(attempt);
541 true
542 }
543 None => false,
544 }
545}
546
547#[cold]
553fn untagged_no_match<O: ?Sized + OpenEnum>(name: &str, state: &State) -> Error {
554 let registered = state
555 .get::<OpenEnums>()
556 .is_some_and(|registry| registry.get::<O>().is_some());
557 if !registered {
558 return Unregistered::<O>::new().error();
559 }
560 no_matching_variant(name, state)
561}
562
563fn names<O: ?Sized + OpenEnum>(state: &State) -> Vec<&str> {
565 match state
566 .get::<OpenEnums>()
567 .and_then(|registry| registry.get::<O>())
568 {
569 Some(registered) => registered.names.iter().map(|name| &**name).collect(),
570 None => Vec::new(),
571 }
572}
573
574fn no_unit<E>(_tag: Tag<'_>) -> Option<E> {
577 None
578}
579
580pub fn deserialize_box<'out, 'de, O: ?Sized + OpenEnum>(
582 out: &'out mut Option<Box<O>>,
583 state: &mut State,
584) -> SinkHandle<'out, 'de> {
585 let name = O::INFO.name;
586 if let OpenRepr::Untagged = O::INFO.repr {
587 return untagged_handle_with(
588 out,
589 name,
590 untagged_variants::<O>,
591 untagged_no_match::<O>,
592 state,
593 );
594 }
595 let variants = Variants {
596 lookup: lookup::<O>,
597 other: None,
598 default: None,
599 names: VariantNames::Dynamic(names::<O>),
600 };
601 match O::INFO.repr {
602 OpenRepr::External => ExternallyTaggedSink::handle(out, name, variants, no_unit, state),
603 OpenRepr::Internal { tag } => InternallyTaggedSink::handle(out, tag, name, variants, state),
604 OpenRepr::Adjacent {
605 tag,
606 content,
607 deny_unknown_fields,
608 } => AdjacentlyTaggedSink::handle(
609 out,
610 tag,
611 content,
612 name,
613 variants,
614 deny_unknown_fields,
615 state,
616 ),
617 OpenRepr::Untagged => unreachable!("untagged open enums are handled above"),
618 }
619}
620
621pub fn deserialize_arc<'out, 'de, O: ?Sized + OpenEnum>(
623 out: &'out mut Option<Arc<O>>,
624 state: &mut State,
625) -> SinkHandle<'out, 'de>
626where
627 Box<O>: Deserialize<'de>,
628{
629 mapped(
630 out,
631 OwnedSink::<Box<O>>::deserialize(state),
632 |value| Ok(Arc::from(value)),
633 state,
634 )
635}
636
637struct Unregistered<O: ?Sized>(PhantomData<fn() -> Box<O>>);
640
641impl<O: ?Sized + OpenEnum> Unregistered<O> {
642 fn new() -> Self {
643 Unregistered(PhantomData)
644 }
645
646 fn error(&self) -> Error {
647 Error::new(
648 ErrorKind::Configuration,
649 alloc::format!(
650 "no variants of {} are registered (register them in a deser::OpenEnums \
651 that is given in the context)",
652 O::INFO.name
653 ),
654 )
655 }
656}
657
658impl<'de, O: ?Sized + OpenEnum> VariantBuilder<'de, Box<O>> for Unregistered<O> {
659 fn sink(&mut self) -> &mut dyn Sink<'de> {
660 self
661 }
662
663 fn build(&mut self) -> Option<Box<O>> {
664 None
665 }
666}
667
668impl<'de, O: ?Sized + OpenEnum> Sink<'de> for Unregistered<O> {
669 fn atom(&mut self, _atom: Atom, _state: &mut State) -> Result<(), Error> {
670 Err(self.error())
671 }
672
673 fn map(&mut self, _state: &mut State) -> Result<(), Error> {
674 Err(self.error())
675 }
676
677 fn seq(&mut self, _state: &mut State) -> Result<(), Error> {
678 Err(self.error())
679 }
680
681 fn finish(&mut self, _state: &mut State) -> Result<(), Error> {
682 Err(self.error())
683 }
684}