1use eure_document::parse::{FromEure, ParseContext, ParseError, ParseErrorKind};
7
8#[derive(Debug, Clone, PartialEq, Eq, Hash, Default)]
10pub enum VariantRepr {
11 #[default]
16 External,
17 Internal { tag: String },
19 Adjacent { tag: String, content: String },
21 Untagged,
23}
24
25#[derive(Debug, Clone, PartialEq, Default, eure_macros::FromEure)]
27#[eure(crate = eure_document, rename_all = "kebab-case")]
28pub struct UnionInterop {
29 #[eure(default)]
31 pub variant_repr: Option<VariantRepr>,
32}
33
34impl FromEure<'_> for VariantRepr {
35 type Error = ParseError;
36
37 fn parse(ctx: &ParseContext<'_>) -> Result<Self, Self::Error> {
38 if let Ok(value) = ctx.parse::<&str>() {
39 return match value {
40 "external" => Ok(VariantRepr::External),
41 "untagged" => Ok(VariantRepr::Untagged),
42 "internal" => Ok(VariantRepr::Internal {
43 tag: "type".to_string(),
44 }),
45 "adjacent" => Ok(VariantRepr::Adjacent {
46 tag: "type".to_string(),
47 content: "content".to_string(),
48 }),
49 _ => Err(ParseError {
50 node_id: ctx.node_id(),
51 kind: ParseErrorKind::UnknownVariant(value.to_string()),
52 }),
53 };
54 }
55
56 let rec = ctx.parse_record()?;
57 let tag = rec.parse_field_optional::<String>("tag")?;
58 let content = rec.parse_field_optional::<String>("content")?;
59 rec.allow_unknown_fields()?;
60
61 match (tag, content) {
62 (Some(tag), Some(content)) => Ok(VariantRepr::Adjacent { tag, content }),
63 (Some(tag), None) => Ok(VariantRepr::Internal { tag }),
64 (None, None) => Ok(VariantRepr::External),
65 (None, Some(_)) => Err(ParseError {
66 node_id: ctx.node_id(),
67 kind: ParseErrorKind::MissingField(
68 "tag (required when content is present)".to_string(),
69 ),
70 }),
71 }
72 }
73}
74
75#[cfg(test)]
76mod tests {
77 use super::*;
78
79 #[test]
80 fn variant_repr_default_is_external() {
81 assert_eq!(VariantRepr::default(), VariantRepr::External);
82 }
83
84 #[test]
85 fn union_interop_default_has_no_variant_repr() {
86 assert_eq!(UnionInterop::default().variant_repr, None);
87 }
88}