svd2rust 0.32.0

Generate Rust register maps (`struct`s) from SVD files
Documentation
use proc_macro2::{Ident, Span, TokenStream};
use quote::{quote, ToTokens};

#[derive(Clone, Debug)]
pub enum Accessor {
    Reg(RegAccessor),
    RawReg(RawRegAccessor),
    Array(ArrayAccessor),
    RawArray(RawArrayAccessor),
    ArrayElem(ArrayElemAccessor),
}

impl Accessor {
    pub fn raw(self) -> Self {
        match self {
            Self::RawReg(_) | Self::RawArray(_) | Self::ArrayElem(_) => self,
            Self::Reg(a) => RawRegAccessor {
                doc: a.doc,
                name: a.name,
                ty: a.ty,
                offset: a.offset,
            }
            .into(),
            Self::Array(a) => RawArrayAccessor {
                doc: a.doc,
                name: a.name,
                ty: a.ty,
                offset: a.offset,
                dim: a.dim,
                increment: a.increment,
            }
            .into(),
        }
    }
}

impl ToTokens for Accessor {
    fn to_tokens(&self, tokens: &mut TokenStream) {
        match self {
            Self::Reg(a) => a.to_tokens(tokens),
            Self::RawReg(a) => a.to_tokens(tokens),
            Self::Array(a) => a.to_tokens(tokens),
            Self::RawArray(a) => a.to_tokens(tokens),
            Self::ArrayElem(a) => a.to_tokens(tokens),
        }
    }
}

impl From<RegAccessor> for Accessor {
    fn from(value: RegAccessor) -> Self {
        Self::Reg(value)
    }
}

impl From<RawRegAccessor> for Accessor {
    fn from(value: RawRegAccessor) -> Self {
        Self::RawReg(value)
    }
}

impl From<ArrayAccessor> for Accessor {
    fn from(value: ArrayAccessor) -> Self {
        Self::Array(value)
    }
}

impl From<RawArrayAccessor> for Accessor {
    fn from(value: RawArrayAccessor) -> Self {
        Self::RawArray(value)
    }
}

impl From<ArrayElemAccessor> for Accessor {
    fn from(value: ArrayElemAccessor) -> Self {
        Self::ArrayElem(value)
    }
}

#[derive(Clone, Debug)]
pub struct RegAccessor {
    pub doc: String,
    pub name: Ident,
    pub ty: syn::Type,
    pub offset: syn::LitInt,
}

impl ToTokens for RegAccessor {
    fn to_tokens(&self, tokens: &mut TokenStream) {
        let Self { doc, name, ty, .. } = self;
        quote! {
            #[doc = #doc]
            #[inline(always)]
            pub const fn #name(&self) -> &#ty {
                &self.#name
            }
        }
        .to_tokens(tokens);
    }
}

#[derive(Clone, Debug)]
pub struct RawRegAccessor {
    pub doc: String,
    pub name: Ident,
    pub ty: syn::Type,
    pub offset: syn::LitInt,
}

impl ToTokens for RawRegAccessor {
    fn to_tokens(&self, tokens: &mut TokenStream) {
        let Self {
            doc,
            name,
            ty,
            offset,
        } = self;
        quote! {
            #[doc = #doc]
            #[inline(always)]
            pub const fn #name(&self) -> &#ty {
                unsafe { &*(self as *const Self).cast::<u8>().add(#offset).cast() }
            }
        }
        .to_tokens(tokens);
    }
}

#[derive(Clone, Debug)]
pub struct ArrayAccessor {
    pub doc: String,
    pub name: Ident,
    pub ty: syn::Type,
    pub offset: syn::LitInt,
    pub dim: syn::LitInt,
    pub increment: syn::LitInt,
}

impl ToTokens for ArrayAccessor {
    fn to_tokens(&self, tokens: &mut TokenStream) {
        let Self { doc, name, ty, .. } = self;
        let name_iter = Ident::new(&format!("{name}_iter"), Span::call_site());
        quote! {
            #[doc = #doc]
            #[inline(always)]
            pub const fn #name(&self, n: usize) -> &#ty {
                &self.#name[n]
            }
            #[doc = "Iterator for array of:"]
            #[doc = #doc]
            #[inline(always)]
            pub fn #name_iter(&self) -> impl Iterator<Item=&#ty> {
                self.#name.iter()
            }
        }
        .to_tokens(tokens);
    }
}

#[derive(Clone, Debug)]
pub struct RawArrayAccessor {
    pub doc: String,
    pub name: Ident,
    pub ty: syn::Type,
    pub offset: syn::LitInt,
    pub dim: syn::LitInt,
    pub increment: syn::LitInt,
}

impl ToTokens for RawArrayAccessor {
    fn to_tokens(&self, tokens: &mut TokenStream) {
        let Self {
            doc,
            name,
            ty,
            offset,
            dim,
            increment,
        } = self;
        let name_iter = Ident::new(&format!("{name}_iter"), Span::call_site());
        let cast = quote! { unsafe { &*(self as *const Self).cast::<u8>().add(#offset).add(#increment * n).cast() } };
        quote! {
            #[doc = #doc]
            #[inline(always)]
            pub const fn #name(&self, n: usize) -> &#ty {
                #[allow(clippy::no_effect)]
                [(); #dim][n];
                #cast
            }
            #[doc = "Iterator for array of:"]
            #[doc = #doc]
            #[inline(always)]
            pub fn #name_iter(&self) -> impl Iterator<Item=&#ty> {
                (0..#dim).map(move |n| #cast)
            }
        }
        .to_tokens(tokens);
    }
}

#[derive(Clone, Debug)]
pub struct ArrayElemAccessor {
    pub doc: String,
    pub name: Ident,
    pub ty: syn::Type,
    pub basename: Ident,
    pub i: syn::LitInt,
}

impl ToTokens for ArrayElemAccessor {
    fn to_tokens(&self, tokens: &mut TokenStream) {
        let Self {
            doc,
            name,
            ty,
            basename,
            i,
        } = &self;
        quote! {
            #[doc = #doc]
            #[inline(always)]
            pub const fn #name(&self) -> &#ty {
                self.#basename(#i)
            }
        }
        .to_tokens(tokens);
    }
}