Skip to content

Accessor newtypes #465

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Aug 8, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 25 additions & 20 deletions src/generate/generic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,20 @@ pub trait RegisterSpec {
/// Trait implemented by readable registers to enable the `read` method.
///
/// Registers marked with `Writable` can be also `modify`'ed.
pub trait Readable: RegisterSpec {}
pub trait Readable: RegisterSpec {
/// Result from a call to `read` and argument to `modify`.
type Reader: core::convert::From<R<Self>> + core::ops::Deref<Target = R<Self>>;
}

/// Trait implemented by writeable registers.
///
/// This enables the `write`, `write_with_zero` and `reset` methods.
///
/// Registers marked with `Readable` can be also `modify`'ed.
pub trait Writable: RegisterSpec {}
pub trait Writable: RegisterSpec {
/// Writer type argument to `write`, et al.
type Writer: core::convert::From<W<Self>> + core::ops::Deref<Target = W<Self>>;
}

/// Reset value of the register.
///
Expand Down Expand Up @@ -61,11 +67,11 @@ impl<REG: Readable> Reg<REG> {
/// let flag = reader.field2().bit_is_set();
/// ```
#[inline(always)]
pub fn read(&self) -> R<REG> {
R {
pub fn read(&self) -> REG::Reader {
REG::Reader::from(R {
bits: self.register.get(),
_reg: marker::PhantomData,
}
})
}
}

Expand Down Expand Up @@ -96,13 +102,13 @@ impl<REG: Resettable + Writable> Reg<REG> {
#[inline(always)]
pub fn write<F>(&self, f: F)
where
F: FnOnce(&mut W<REG>) -> &mut W<REG>,
F: FnOnce(&mut REG::Writer) -> &mut REG::Writer,
{
self.register.set(
f(&mut W {
f(&mut REG::Writer::from(W {
bits: REG::reset_value(),
_reg: marker::PhantomData,
})
}))
.bits,
);
}
Expand All @@ -118,13 +124,13 @@ where
#[inline(always)]
pub fn write_with_zero<F>(&self, f: F)
where
F: FnOnce(&mut W<REG>) -> &mut W<REG>,
F: FnOnce(&mut REG::Writer) -> &mut REG::Writer,
{
self.register.set(
f(&mut W {
(*f(&mut REG::Writer::from(W {
bits: REG::Ux::default(),
_reg: marker::PhantomData,
})
})))
.bits,
);
}
Expand All @@ -151,19 +157,19 @@ impl<REG: Readable + Writable> Reg<REG> {
#[inline(always)]
pub fn modify<F>(&self, f: F)
where
for<'w> F: FnOnce(&R<REG>, &'w mut W<REG>) -> &'w mut W<REG>,
for<'w> F: FnOnce(&REG::Reader, &'w mut REG::Writer) -> &'w mut REG::Writer,
{
let bits = self.register.get();
self.register.set(
f(
&R {
&REG::Reader::from(R {
bits,
_reg: marker::PhantomData,
},
&mut W {
}),
&mut REG::Writer::from(W {
bits,
_reg: marker::PhantomData,
},
}),
)
.bits,
);
Expand All @@ -174,7 +180,7 @@ impl<REG: Readable + Writable> Reg<REG> {
///
/// Result of the `read` methods of registers. Also used as a closure argument in the `modify`
/// method.
pub struct R<REG: RegisterSpec> {
pub struct R<REG: RegisterSpec + ?Sized> {
pub(crate) bits: REG::Ux,
_reg: marker::PhantomData<REG>,
}
Expand All @@ -201,7 +207,7 @@ where
/// Register writer.
///
/// Used as an argument to the closures in the `write` and `modify` methods of the register.
pub struct W<REG: RegisterSpec> {
pub struct W<REG: RegisterSpec + ?Sized> {
///Writable bits
pub(crate) bits: REG::Ux,
_reg: marker::PhantomData<REG>,
Expand All @@ -210,9 +216,8 @@ pub struct W<REG: RegisterSpec> {
impl<REG: RegisterSpec> W<REG> {
/// Writes raw bits to the register.
#[inline(always)]
pub unsafe fn bits(&mut self, bits: REG::Ux) -> &mut Self {
pub unsafe fn bits(&mut self, bits: REG::Ux) {
self.bits = bits;
self
}
}

Expand Down
108 changes: 100 additions & 8 deletions src/generate/register.rs
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,22 @@ pub fn render(
let desc = format!("Reader of register {}", register.name);
mod_items.extend(quote! {
#[doc = #desc]
pub type R = crate::R<#name_uc_spec>;
pub struct R(crate::R<#name_uc_spec>);

impl core::ops::Deref for R {
type Target = crate::R<#name_uc_spec>;

#[inline(always)]
fn deref(&self) -> &Self::Target {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add #[inline(always)] for each Deref and DerefMut first and retest.
Do you use cargo size from cargo-binutils or something else?

Copy link
Contributor Author

@couchand couchand Aug 7, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That did it! Now it's exactly the same size.

These numbers are from my system avr-size. I just tried with cargo-binutils and I'm getting 'Failed to parse crate metadata'.

&self.0
}
}

impl core::convert::From<crate::R<#name_uc_spec>> for R {
fn from(reader: crate::R<#name_uc_spec>) -> Self {
R(reader)
}
}
});
methods.push("read");
}
Expand All @@ -66,7 +81,29 @@ pub fn render(
let desc = format!("Writer for register {}", register.name);
mod_items.extend(quote! {
#[doc = #desc]
pub type W = crate::W<#name_uc_spec>;
pub struct W(crate::W<#name_uc_spec>);

impl core::ops::Deref for W {
type Target = crate::W<#name_uc_spec>;

#[inline(always)]
fn deref(&self) -> &Self::Target {
&self.0
}
}

impl core::ops::DerefMut for W {
#[inline(always)]
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.0
}
}

impl core::convert::From<crate::W<#name_uc_spec>> for W {
fn from(writer: crate::W<#name_uc_spec>) -> Self {
W(writer)
}
}
});
methods.push("write_with_zero");
if can_reset {
Expand Down Expand Up @@ -125,6 +162,14 @@ pub fn render(

mod_items.extend(w_impl_items);

mod_items.extend(quote! {
#[doc = "Writes raw bits to the register."]
pub unsafe fn bits(&mut self, bits: #rty) -> &mut Self {
self.0.bits(bits);
self
}
});

close.to_tokens(&mut mod_items);
}

Expand Down Expand Up @@ -167,7 +212,9 @@ pub fn render(
);
mod_items.extend(quote! {
#[doc = #doc]
impl crate::Readable for #name_uc_spec {}
impl crate::Readable for #name_uc_spec {
type Reader = R;
}
});
}
if can_write {
Expand All @@ -177,7 +224,9 @@ pub fn render(
);
mod_items.extend(quote! {
#[doc = #doc]
impl crate::Writable for #name_uc_spec {}
impl crate::Writable for #name_uc_spec {
type Writer = W;
}
});
}
if let Some(rv) = res_val.map(util::hex) {
Expand Down Expand Up @@ -388,7 +437,22 @@ pub fn fields(

mod_items.extend(quote! {
#[doc = #readerdoc]
pub type #name_pc_r = crate::FieldReader<#fty, #name_pc_a>;
pub struct #name_pc_r(crate::FieldReader<#fty, #name_pc_a>);

impl #name_pc_r {
pub(crate) fn new(bits: #fty) -> Self {
#name_pc_r(crate::FieldReader::new(bits))
}
}

impl core::ops::Deref for #name_pc_r {
type Target = crate::FieldReader<#fty, #name_pc_a>;

#[inline(always)]
fn deref(&self) -> &Self::Target {
&self.0
}
}
});
} else {
let has_reserved_variant = evs.values.len() != (1 << width);
Expand Down Expand Up @@ -463,23 +527,51 @@ pub fn fields(
#[doc = #doc]
#inline
pub fn #is_variant(&self) -> bool {
*self == #name_pc_a::#pc
**self == #name_pc_a::#pc
}
});
}

mod_items.extend(quote! {
#[doc = #readerdoc]
pub type #name_pc_r = crate::FieldReader<#fty, #name_pc_a>;
pub struct #name_pc_r(crate::FieldReader<#fty, #name_pc_a>);

impl #name_pc_r {
pub(crate) fn new(bits: #fty) -> Self {
#name_pc_r(crate::FieldReader::new(bits))
}
#enum_items
}

impl core::ops::Deref for #name_pc_r {
type Target = crate::FieldReader<#fty, #name_pc_a>;

#[inline(always)]
fn deref(&self) -> &Self::Target {
&self.0
}
}
});
}
} else {
mod_items.extend(quote! {
#[doc = #readerdoc]
pub type #name_pc_r = crate::FieldReader<#fty, #fty>;
pub struct #name_pc_r(crate::FieldReader<#fty, #fty>);

impl #name_pc_r {
pub(crate) fn new(bits: #fty) -> Self {
#name_pc_r(crate::FieldReader::new(bits))
}
}

impl core::ops::Deref for #name_pc_r {
type Target = crate::FieldReader<#fty, #fty>;

#[inline(always)]
fn deref(&self) -> &Self::Target {
&self.0
}
}
})
}
}
Expand Down