Skip to content

Commit 78e4864

Browse files
authored
Merge pull request #829 from rust-embedded/write_enum
add IsEnum & rm FieldWriterSafe, add set
2 parents 6f5479e + 595c6dc commit 78e4864

File tree

3 files changed

+80
-65
lines changed

3 files changed

+80
-65
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/).
77

88
## [Unreleased]
99

10+
- Add `IsEnum` constraint for `FieldWriter`s (fix `variant` safety)
11+
- Make field writer `bits` always `unsafe` add `set` for safe writing
1012
- Fix bit writer type for `ModifiedWriteValues::ZeroToSet`
1113

1214
## [v0.32.0] - 2024-02-26

src/generate/generic.rs

Lines changed: 25 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,9 @@ pub trait FieldSpec: Sized {
5656
type Ux: Copy + PartialEq + From<Self>;
5757
}
5858

59+
/// Marker for fields with fixed values
60+
pub trait IsEnum: FieldSpec {}
61+
5962
/// Trait implemented by readable registers to enable the `read` method.
6063
///
6164
/// Registers marked with `Writable` can be also be `modify`'ed.
@@ -474,16 +477,13 @@ pub struct Safe;
474477
/// You should check that value is allowed to pass to register/field writer marked with this
475478
pub struct Unsafe;
476479

477-
/// Write field Proxy with unsafe `bits`
478-
pub type FieldWriter<'a, REG, const WI: u8, FI = u8> = raw::FieldWriter<'a, REG, WI, FI, Unsafe>;
479-
/// Write field Proxy with safe `bits`
480-
pub type FieldWriterSafe<'a, REG, const WI: u8, FI = u8> = raw::FieldWriter<'a, REG, WI, FI, Safe>;
480+
/// Write field Proxy
481+
pub type FieldWriter<'a, REG, const WI: u8, FI = u8, Safety = Unsafe> = raw::FieldWriter<'a, REG, WI, FI, Safety>;
481482

482-
impl<'a, REG, const WI: u8, FI> FieldWriter<'a, REG, WI, FI>
483+
impl<'a, REG, const WI: u8, FI, Safety> FieldWriter<'a, REG, WI, FI, Safety>
483484
where
484485
REG: Writable + RegisterSpec,
485486
FI: FieldSpec,
486-
REG::Ux: From<FI::Ux>,
487487
{
488488
/// Field width
489489
pub const WIDTH: u8 = WI;
@@ -499,7 +499,14 @@ where
499499
pub const fn offset(&self) -> u8 {
500500
self.o
501501
}
502+
}
502503

504+
impl<'a, REG, const WI: u8, FI, Safety> FieldWriter<'a, REG, WI, FI, Safety>
505+
where
506+
REG: Writable + RegisterSpec,
507+
FI: FieldSpec,
508+
REG::Ux: From<FI::Ux>,
509+
{
503510
/// Writes raw bits to the field
504511
///
505512
/// # Safety
@@ -511,45 +518,31 @@ where
511518
self.w.bits |= (REG::Ux::from(value) & REG::Ux::mask::<WI>()) << self.o;
512519
self.w
513520
}
514-
/// Writes `variant` to the field
515-
#[inline(always)]
516-
pub fn variant(self, variant: FI) -> &'a mut W<REG> {
517-
unsafe { self.bits(FI::Ux::from(variant)) }
518-
}
519521
}
520522

521-
impl<'a, REG, const WI: u8, FI> FieldWriterSafe<'a, REG, WI, FI>
523+
impl<'a, REG, const WI: u8, FI> FieldWriter<'a, REG, WI, FI, Safe>
522524
where
523525
REG: Writable + RegisterSpec,
524526
FI: FieldSpec,
525527
REG::Ux: From<FI::Ux>,
526528
{
527-
/// Field width
528-
pub const WIDTH: u8 = WI;
529-
530-
/// Field width
531-
#[inline(always)]
532-
pub const fn width(&self) -> u8 {
533-
WI
534-
}
535-
536-
/// Field offset
537-
#[inline(always)]
538-
pub const fn offset(&self) -> u8 {
539-
self.o
540-
}
541-
542529
/// Writes raw bits to the field
543530
#[inline(always)]
544-
pub fn bits(self, value: FI::Ux) -> &'a mut W<REG> {
545-
self.w.bits &= !(REG::Ux::mask::<WI>() << self.o);
546-
self.w.bits |= (REG::Ux::from(value) & REG::Ux::mask::<WI>()) << self.o;
547-
self.w
531+
pub fn set(self, value: FI::Ux) -> &'a mut W<REG> {
532+
unsafe { self.bits(value) }
548533
}
534+
}
535+
536+
impl<'a, REG, const WI: u8, FI, Safety> FieldWriter<'a, REG, WI, FI, Safety>
537+
where
538+
REG: Writable + RegisterSpec,
539+
FI: IsEnum,
540+
REG::Ux: From<FI::Ux>,
541+
{
549542
/// Writes `variant` to the field
550543
#[inline(always)]
551544
pub fn variant(self, variant: FI) -> &'a mut W<REG> {
552-
self.bits(FI::Ux::from(variant))
545+
unsafe { self.bits(FI::Ux::from(variant)) }
553546
}
554547
}
555548

src/generate/register.rs

Lines changed: 53 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -393,17 +393,22 @@ pub fn render_register_mod(
393393
// * there is a single field that covers the entire register
394394
// * that field can represent all values
395395
// * the write constraints of the register allow full range of values
396-
let can_write_safe = !unsafety(
396+
let safe_ty = if let Safety::Safe = Safety::get(
397397
register
398398
.fields
399399
.as_ref()
400400
.and_then(|fields| fields.first())
401401
.and_then(|field| field.write_constraint)
402402
.as_ref(),
403403
rsize,
404-
) || !unsafety(register.write_constraint.as_ref(), rsize);
405-
let safe_ty = if can_write_safe { "Safe" } else { "Unsafe" };
406-
let safe_ty = Ident::new(safe_ty, span);
404+
) {
405+
Safety::Safe
406+
} else if let Safety::Safe = Safety::get(register.write_constraint.as_ref(), rsize) {
407+
Safety::Safe
408+
} else {
409+
Safety::Unsafe
410+
};
411+
let safe_ty = safe_ty.ident(span);
407412

408413
let doc = format!("`write(|w| ..)` method takes [`{mod_ty}::W`](W) writer structure",);
409414

@@ -1097,7 +1102,7 @@ pub fn fields(
10971102
// the read value, or else we reuse read value.
10981103
if can_write {
10991104
let mut proxy_items = TokenStream::new();
1100-
let mut unsafety = unsafety(f.write_constraint.as_ref(), width);
1105+
let mut safety = Safety::get(f.write_constraint.as_ref(), width);
11011106

11021107
// if we writes to enumeratedValues, generate its structure if it differs from read structure.
11031108
let value_write_ty = if let Some(ev) = rwenum.write_enum() {
@@ -1136,12 +1141,12 @@ pub fn fields(
11361141
if variants.len() == 1 << width {
11371142
} else if let Some(def) = def.take() {
11381143
variants.push(def);
1139-
unsafety = false;
1144+
safety = Safety::Safe;
11401145
}
11411146

11421147
// if the write structure is finite, it can be safely written.
11431148
if variants.len() == 1 << width {
1144-
unsafety = false;
1149+
safety = Safety::Safe;
11451150
}
11461151

11471152
// generate write value structure and From conversation if we can't reuse read value structure.
@@ -1235,19 +1240,15 @@ pub fn fields(
12351240
quote! { crate::#wproxy<'a, REG, #value_write_ty> }
12361241
}
12371242
} else {
1238-
let wproxy = Ident::new(
1239-
if unsafety {
1240-
"FieldWriter"
1241-
} else {
1242-
"FieldWriterSafe"
1243-
},
1244-
span,
1245-
);
1243+
let wproxy = Ident::new("FieldWriter", span);
12461244
let width = &unsuffixed(width);
1247-
if value_write_ty == "u8" {
1245+
if value_write_ty == "u8" && safety != Safety::Safe {
12481246
quote! { crate::#wproxy<'a, REG, #width> }
1249-
} else {
1247+
} else if safety != Safety::Safe {
12501248
quote! { crate::#wproxy<'a, REG, #width, #value_write_ty> }
1249+
} else {
1250+
let safe_ty = safety.ident(span);
1251+
quote! { crate::#wproxy<'a, REG, #width, #value_write_ty, crate::#safe_ty> }
12511252
}
12521253
};
12531254
mod_items.extend(quote! {
@@ -1370,22 +1371,40 @@ pub fn fields(
13701371
))
13711372
}
13721373

1373-
fn unsafety(write_constraint: Option<&WriteConstraint>, width: u32) -> bool {
1374-
match &write_constraint {
1375-
Some(&WriteConstraint::Range(range))
1376-
if range.min == 0 && range.max == u64::MAX >> (64 - width) =>
1377-
{
1378-
// the SVD has acknowledged that it's safe to write
1379-
// any value that can fit in the field
1380-
false
1381-
}
1382-
None if width == 1 => {
1383-
// the field is one bit wide, so we assume it's legal to write
1384-
// either value into it or it wouldn't exist; despite that
1385-
// if a writeConstraint exists then respect it
1386-
false
1374+
#[derive(Clone, Debug, PartialEq, Eq)]
1375+
enum Safety {
1376+
Unsafe,
1377+
Safe,
1378+
}
1379+
1380+
impl Safety {
1381+
fn get(write_constraint: Option<&WriteConstraint>, width: u32) -> Self {
1382+
match &write_constraint {
1383+
Some(&WriteConstraint::Range(range))
1384+
if range.min == 0 && range.max == u64::MAX >> (64 - width) =>
1385+
{
1386+
// the SVD has acknowledged that it's safe to write
1387+
// any value that can fit in the field
1388+
Self::Safe
1389+
}
1390+
None if width == 1 => {
1391+
// the field is one bit wide, so we assume it's legal to write
1392+
// either value into it or it wouldn't exist; despite that
1393+
// if a writeConstraint exists then respect it
1394+
Self::Safe
1395+
}
1396+
_ => Self::Unsafe,
13871397
}
1388-
_ => true,
1398+
}
1399+
fn ident(&self, span: Span) -> Ident {
1400+
Ident::new(
1401+
if let Self::Safe = self {
1402+
"Safe"
1403+
} else {
1404+
"Unsafe"
1405+
},
1406+
span,
1407+
)
13891408
}
13901409
}
13911410

@@ -1425,7 +1444,7 @@ impl Variant {
14251444
span,
14261445
);
14271446
let sc = case.sanitize(&ev.name);
1428-
const INTERNALS: [&str; 4] = ["set_bit", "clear_bit", "bit", "bits"];
1447+
const INTERNALS: [&str; 6] = ["bit", "bits", "clear_bit", "set", "set_bit", "variant"];
14291448
let sc = Ident::new(
14301449
&(if INTERNALS.contains(&sc.as_ref()) {
14311450
sc + "_"
@@ -1552,6 +1571,7 @@ fn add_from_variants<'a>(
15521571
impl crate::FieldSpec for #pc {
15531572
type Ux = #fty;
15541573
}
1574+
impl crate::IsEnum for #pc {}
15551575
});
15561576
}
15571577
}

0 commit comments

Comments
 (0)