Skip to content

Commit 0138b99

Browse files
authored
Merge pull request #832 from rust-embedded/range-set
field::set with range assert
2 parents 08dd33e + ff15953 commit 0138b99

File tree

3 files changed

+90
-21
lines changed

3 files changed

+90
-21
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 checked `set` for not full safe fields
11+
1012
## [v0.33.0] - 2024-03-26
1113

1214
- Add `IsEnum` constraint for `FieldWriter`s (fix `variant` safety)

src/generate/generic.rs

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -476,6 +476,12 @@ impl<FI> BitReader<FI> {
476476
pub struct Safe;
477477
/// You should check that value is allowed to pass to register/field writer marked with this
478478
pub struct Unsafe;
479+
/// Marker for field writers are safe to write in specified inclusive range
480+
pub struct Range<const MIN: u64, const MAX: u64>;
481+
/// Marker for field writers are safe to write in specified inclusive range
482+
pub struct RangeFrom<const MIN: u64>;
483+
/// Marker for field writers are safe to write in specified inclusive range
484+
pub struct RangeTo<const MAX: u64>;
479485

480486
/// Write field Proxy
481487
pub type FieldWriter<'a, REG, const WI: u8, FI = u8, Safety = Unsafe> = raw::FieldWriter<'a, REG, WI, FI, Safety>;
@@ -533,6 +539,60 @@ where
533539
}
534540
}
535541

542+
impl<'a, REG, const WI: u8, FI, const MIN: u64, const MAX: u64> FieldWriter<'a, REG, WI, FI, Range<MIN, MAX>>
543+
where
544+
REG: Writable + RegisterSpec,
545+
FI: FieldSpec,
546+
REG::Ux: From<FI::Ux>,
547+
u64: From<FI::Ux>,
548+
{
549+
/// Writes raw bits to the field
550+
#[inline(always)]
551+
pub fn set(self, value: FI::Ux) -> &'a mut W<REG> {
552+
{
553+
let value = u64::from(value);
554+
assert!(value >= MIN && value <= MAX);
555+
}
556+
unsafe { self.bits(value) }
557+
}
558+
}
559+
560+
impl<'a, REG, const WI: u8, FI, const MIN: u64> FieldWriter<'a, REG, WI, FI, RangeFrom<MIN>>
561+
where
562+
REG: Writable + RegisterSpec,
563+
FI: FieldSpec,
564+
REG::Ux: From<FI::Ux>,
565+
u64: From<FI::Ux>,
566+
{
567+
/// Writes raw bits to the field
568+
#[inline(always)]
569+
pub fn set(self, value: FI::Ux) -> &'a mut W<REG> {
570+
{
571+
let value = u64::from(value);
572+
assert!(value >= MIN);
573+
}
574+
unsafe { self.bits(value) }
575+
}
576+
}
577+
578+
impl<'a, REG, const WI: u8, FI, const MAX: u64> FieldWriter<'a, REG, WI, FI, RangeTo<MAX>>
579+
where
580+
REG: Writable + RegisterSpec,
581+
FI: FieldSpec,
582+
REG::Ux: From<FI::Ux>,
583+
u64: From<FI::Ux>,
584+
{
585+
/// Writes raw bits to the field
586+
#[inline(always)]
587+
pub fn set(self, value: FI::Ux) -> &'a mut W<REG> {
588+
{
589+
let value = u64::from(value);
590+
assert!(value <= MAX);
591+
}
592+
unsafe { self.bits(value) }
593+
}
594+
}
595+
536596
impl<'a, REG, const WI: u8, FI, Safety> FieldWriter<'a, REG, WI, FI, Safety>
537597
where
538598
REG: Writable + RegisterSpec,

src/generate/register.rs

Lines changed: 28 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
use crate::svd::{
22
self, Access, BitRange, DimElement, EnumeratedValue, EnumeratedValues, Field, MaybeArray,
33
ModifiedWriteValues, ReadAction, Register, RegisterProperties, Usage, WriteConstraint,
4+
WriteConstraintRange,
45
};
56
use core::u64;
67
use log::warn;
@@ -408,7 +409,7 @@ pub fn render_register_mod(
408409
} else {
409410
Safety::Unsafe
410411
};
411-
let safe_ty = safe_ty.ident(span);
412+
let safe_ty = safe_ty.ident(rsize);
412413

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

@@ -1138,17 +1139,14 @@ pub fn fields(
11381139
.map(|v| Variant::from_value(v, def, config))
11391140
})
11401141
.transpose()?;
1142+
// if the write structure is finite, it can be safely written.
11411143
if variants.len() == 1 << width {
1144+
safety = Safety::Safe;
11421145
} else if let Some(def) = def.take() {
11431146
variants.push(def);
11441147
safety = Safety::Safe;
11451148
}
11461149

1147-
// if the write structure is finite, it can be safely written.
1148-
if variants.len() == 1 << width {
1149-
safety = Safety::Safe;
1150-
}
1151-
11521150
// generate write value structure and From conversation if we can't reuse read value structure.
11531151
if rwenum.generate_write_enum() {
11541152
if variants.is_empty() {
@@ -1241,14 +1239,14 @@ pub fn fields(
12411239
}
12421240
} else {
12431241
let wproxy = Ident::new("FieldWriter", span);
1244-
let width = &unsuffixed(width);
1242+
let uwidth = &unsuffixed(width);
12451243
if value_write_ty == "u8" && safety != Safety::Safe {
1246-
quote! { crate::#wproxy<'a, REG, #width> }
1244+
quote! { crate::#wproxy<'a, REG, #uwidth> }
12471245
} else if safety != Safety::Safe {
1248-
quote! { crate::#wproxy<'a, REG, #width, #value_write_ty> }
1246+
quote! { crate::#wproxy<'a, REG, #uwidth, #value_write_ty> }
12491247
} else {
1250-
let safe_ty = safety.ident(span);
1251-
quote! { crate::#wproxy<'a, REG, #width, #value_write_ty, crate::#safe_ty> }
1248+
let safe_ty = safety.ident(width);
1249+
quote! { crate::#wproxy<'a, REG, #uwidth, #value_write_ty, crate::#safe_ty> }
12521250
}
12531251
};
12541252
mod_items.extend(quote! {
@@ -1371,9 +1369,10 @@ pub fn fields(
13711369
))
13721370
}
13731371

1374-
#[derive(Clone, Debug, PartialEq, Eq)]
1372+
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
13751373
enum Safety {
13761374
Unsafe,
1375+
Range(WriteConstraintRange),
13771376
Safe,
13781377
}
13791378

@@ -1393,18 +1392,26 @@ impl Safety {
13931392
// if a writeConstraint exists then respect it
13941393
Self::Safe
13951394
}
1395+
Some(&WriteConstraint::Range(range)) => Self::Range(range),
13961396
_ => Self::Unsafe,
13971397
}
13981398
}
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-
)
1399+
fn ident(&self, width: u32) -> TokenStream {
1400+
match self {
1401+
Self::Safe => quote!(Safe),
1402+
Self::Unsafe => quote!(Unsafe),
1403+
Self::Range(range) => {
1404+
let min = unsuffixed(range.min);
1405+
let max = unsuffixed(range.max);
1406+
if range.min == 0 {
1407+
quote!(RangeTo<#max>)
1408+
} else if range.max == u64::MAX >> (64 - width) {
1409+
quote!(RangeFrom<#min>)
1410+
} else {
1411+
quote!(Range<#min, #max>)
1412+
}
1413+
}
1414+
}
14081415
}
14091416
}
14101417

0 commit comments

Comments
 (0)