Skip to content

Commit 4877d5c

Browse files
Merge #486
486: Fix handling of `isDefault' `enumeratedValue's r=therealprof a=smindinvern Currently, an `enumeratedValue` is ignored if (and only if) it's name matches "reserved", and all remaining `enumeratedValue`s are expected to have a `value` child element. However, the SVD schema allows an `enumeratedValue` to contain *either* a `value` element or an `isDefault` element. When `svd2rust` hits an `isDefault` element that isn't named "reserved", an error is thrown. In general, filtering these out should be safe, as they don't represent specific values that can be assigned to a field, but rather a *range* of values. The ability to read and write such arbitrary values is already handled with the `bits()` method defined on field readers/writers. The one corner case, however, is for fields with only a *single* `enumeratedValue` which has an `isDefault` child element. Attempting to handle these in the usual way results in emitting empty `enum`s which causes compilation failures. Instead, emit a `newtype` encapsulating the field's base type. Co-authored-by: Nickolas Lloyd <smindinvern@users.noreply.github.com>
2 parents 461078b + 76896ab commit 4877d5c

File tree

1 file changed

+119
-80
lines changed

1 file changed

+119
-80
lines changed

src/generate/register.rs

Lines changed: 119 additions & 80 deletions
Original file line numberDiff line numberDiff line change
@@ -442,79 +442,82 @@ pub fn fields(
442442
} else {
443443
let has_reserved_variant = evs.values.len() != (1 << width);
444444
let variants = Variant::from_enumerated_values(evs)?;
445-
446-
add_from_variants(mod_items, &variants, &name_pc_a, &fty, &description, rv);
447-
448445
let mut enum_items = TokenStream::new();
449446

450-
let mut arms = TokenStream::new();
451-
for v in variants.iter().map(|v| {
452-
let i = util::unsuffixed_or_bool(v.value, width);
453-
let pc = &v.pc;
447+
if variants.is_empty() {
448+
add_with_no_variants(mod_items, &name_pc_a, &fty, &description, rv);
449+
} else {
450+
add_from_variants(mod_items, &variants, &name_pc_a, &fty, &description, rv);
454451

455-
if has_reserved_variant {
456-
quote! { #i => Val(#name_pc_a::#pc), }
457-
} else {
458-
quote! { #i => #name_pc_a::#pc, }
452+
let mut arms = TokenStream::new();
453+
for v in variants.iter().map(|v| {
454+
let i = util::unsuffixed_or_bool(v.value, width);
455+
let pc = &v.pc;
456+
457+
if has_reserved_variant {
458+
quote! { #i => Val(#name_pc_a::#pc), }
459+
} else {
460+
quote! { #i => #name_pc_a::#pc, }
461+
}
462+
}) {
463+
arms.extend(v);
459464
}
460-
}) {
461-
arms.extend(v);
462-
}
463465

464-
if has_reserved_variant {
465-
arms.extend(quote! {
466+
if has_reserved_variant {
467+
arms.extend(quote! {
466468
i => Res(i),
467-
});
468-
} else if 1 << width.to_ty_width()? != variants.len() {
469-
arms.extend(quote! {
469+
});
470+
} else if 1 << width.to_ty_width()? != variants.len() {
471+
arms.extend(quote! {
470472
_ => unreachable!(),
471-
});
472-
}
473+
});
474+
}
473475

474-
if has_reserved_variant {
475-
enum_items.extend(quote! {
476+
if has_reserved_variant {
477+
enum_items.extend(quote! {
476478
///Get enumerated values variant
477479
#inline
478480
pub fn variant(&self) -> crate::Variant<#fty, #name_pc_a> {
479-
use crate::Variant::*;
480-
match self.bits {
481-
#arms
482-
}
481+
use crate::Variant::*;
482+
match self.bits {
483+
#arms
484+
}
483485
}
484-
});
485-
} else {
486-
enum_items.extend(quote! {
486+
});
487+
} else {
488+
enum_items.extend(quote! {
487489
///Get enumerated values variant
488490
#inline
489491
pub fn variant(&self) -> #name_pc_a {
490-
match self.bits {
491-
#arms
492-
}
492+
match self.bits {
493+
#arms
494+
}
493495
}
494-
});
495-
}
496-
497-
for v in &variants {
498-
let pc = &v.pc;
499-
let sc = &v.sc;
500-
501-
let is_variant = Ident::new(
502-
&if sc.to_string().starts_with('_') {
503-
format!("is{}", sc)
504-
} else {
505-
format!("is_{}", sc)
506-
},
507-
span,
508-
);
496+
});
497+
}
509498

510-
let doc = format!("Checks if the value of the field is `{}`", pc);
511-
enum_items.extend(quote! {
499+
for v in &variants {
500+
let pc = &v.pc;
501+
let sc = &v.sc;
502+
503+
let is_variant = Ident::new(
504+
&if sc.to_string().starts_with('_') {
505+
format!("is{}", sc)
506+
} else {
507+
format!("is_{}", sc)
508+
},
509+
span,
510+
);
511+
512+
let doc = format!("Checks if the value of the field is `{}`", pc);
513+
enum_items.extend(quote! {
512514
#[doc = #doc]
513515
#inline
514516
pub fn #is_variant(&self) -> bool {
515-
**self == #name_pc_a::#pc
517+
**self == #name_pc_a::#pc
516518
}
517-
});
519+
});
520+
}
518521
}
519522

520523
mod_items.extend(quote! {
@@ -582,43 +585,47 @@ pub fn fields(
582585
let pc = pc.to_sanitized_upper_case();
583586
let base_pc_w = Ident::new(&(pc + "_AW"), span);
584587
derive_from_base(mod_items, &base, &name_pc_aw, &base_pc_w, &description)
588+
} else if variants.is_empty() {
589+
add_with_no_variants(mod_items, name_pc_aw, &fty, &description, rv);
585590
} else {
586591
add_from_variants(mod_items, &variants, name_pc_aw, &fty, &description, rv);
587592
}
588593
}
589594

590-
if unsafety.is_some() {
591-
proxy_items.extend(quote! {
592-
///Writes `variant` to the field
593-
#inline
594-
pub fn variant(self, variant: #name_pc_aw) -> &'a mut W {
595+
if !variants.is_empty() {
596+
if unsafety.is_some() {
597+
proxy_items.extend(quote! {
598+
///Writes `variant` to the field
599+
#inline
600+
pub fn variant(self, variant: #name_pc_aw) -> &'a mut W {
595601
unsafe {
596-
self.#bits(variant.into())
602+
self.#bits(variant.into())
597603
}
598-
}
599-
});
600-
} else {
601-
proxy_items.extend(quote! {
602-
///Writes `variant` to the field
603-
#inline
604-
pub fn variant(self, variant: #name_pc_aw) -> &'a mut W {
605-
self.#bits(variant.into())
606-
}
607-
});
608-
}
604+
}
605+
});
606+
} else {
607+
proxy_items.extend(quote! {
608+
///Writes `variant` to the field
609+
#inline
610+
pub fn variant(self, variant: #name_pc_aw) -> &'a mut W {
611+
self.#bits(variant.into())
612+
}
613+
});
614+
}
609615

610-
for v in &variants {
611-
let pc = &v.pc;
612-
let sc = &v.sc;
616+
for v in &variants {
617+
let pc = &v.pc;
618+
let sc = &v.sc;
613619

614-
let doc = util::escape_brackets(util::respace(&v.doc).as_ref());
615-
proxy_items.extend(quote! {
616-
#[doc = #doc]
617-
#inline
618-
pub fn #sc(self) -> &'a mut W {
620+
let doc = util::escape_brackets(util::respace(&v.doc).as_ref());
621+
proxy_items.extend(quote! {
622+
#[doc = #doc]
623+
#inline
624+
pub fn #sc(self) -> &'a mut W {
619625
self.variant(#name_pc_aw::#pc)
620-
}
621-
});
626+
}
627+
});
628+
}
622629
}
623630
}
624631

@@ -773,7 +780,7 @@ impl Variant {
773780
.iter()
774781
// filter out all reserved variants, as we should not
775782
// generate code for them
776-
.filter(|field| field.name.to_lowercase() != "reserved")
783+
.filter(|field| field.name.to_lowercase() != "reserved" && field.is_default == None)
777784
.map(|ev| {
778785
let value = u64(ev.value.ok_or_else(|| {
779786
anyhow!("EnumeratedValue {} has no `<value>` field", ev.name)
@@ -793,6 +800,38 @@ impl Variant {
793800
}
794801
}
795802

803+
fn add_with_no_variants(
804+
mod_items: &mut TokenStream,
805+
pc: &Ident,
806+
fty: &Ident,
807+
desc: &str,
808+
reset_value: Option<u64>,
809+
) {
810+
let cast = if fty == "bool" {
811+
quote! { val.0 as u8 != 0 }
812+
} else {
813+
quote! { val.0 as _ }
814+
};
815+
816+
let desc = if let Some(rv) = reset_value {
817+
format!("{}\n\nValue on reset: {}", desc, rv)
818+
} else {
819+
desc.to_owned()
820+
};
821+
822+
mod_items.extend(quote! {
823+
#[doc = #desc]
824+
#[derive(Clone, Copy, Debug, PartialEq)]
825+
pub struct #pc(#fty);
826+
impl From<#pc> for #fty {
827+
#[inline(always)]
828+
fn from(val: #pc) -> Self {
829+
#cast
830+
}
831+
}
832+
});
833+
}
834+
796835
fn add_from_variants(
797836
mod_items: &mut TokenStream,
798837
variants: &[Variant],

0 commit comments

Comments
 (0)