Skip to content

Add an option to generate defmt support unconditionally #74

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

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
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
10 changes: 3 additions & 7 deletions src/generate/device.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ use quote::quote;
use crate::ir::*;
use crate::util::{self, StringExt};

use super::sorted;
use super::{sorted, with_defmt_cfg_attr};

pub fn render_device_x(_ir: &IR, d: &Device) -> Result<String> {
let mut device_x = String::new();
Expand Down Expand Up @@ -78,15 +78,11 @@ pub fn render(opts: &super::Options, ir: &IR, d: &Device, path: &str) -> Result<
}
let n = util::unsuffixed(pos as u64);

let defmt = opts.defmt_feature.as_ref().map(|defmt_feature| {
quote! {
#[cfg_attr(feature = #defmt_feature, derive(defmt::Format))]
}
});
let derive_defmt = with_defmt_cfg_attr(&opts.defmt, quote! { derive(defmt::Format) });

out.extend(quote!(
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
#defmt
#derive_defmt
pub enum Interrupt {
#interrupts
}
Expand Down
15 changes: 5 additions & 10 deletions src/generate/enumm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ use quote::quote;
use crate::ir::*;
use crate::util;

use super::sorted;
use super::{sorted, with_defmt_cfg, with_defmt_cfg_attr};

pub fn render(opts: &super::Options, _ir: &IR, e: &Enum, path: &str) -> Result<TokenStream> {
let span = Span::call_site();
Expand Down Expand Up @@ -55,9 +55,8 @@ pub fn render(opts: &super::Options, _ir: &IR, e: &Enum, path: &str) -> Result<T
));
}

let defmt = opts.defmt_feature.as_ref().map(|defmt_feature| {
let impl_defmt = with_defmt_cfg(&opts.defmt, || {
quote! {
#[cfg(feature = #defmt_feature)]
impl defmt::Format for #name {
fn format(&self, f: defmt::Formatter) {
match self.0 {
Expand Down Expand Up @@ -102,7 +101,7 @@ pub fn render(opts: &super::Options, _ir: &IR, e: &Enum, path: &str) -> Result<T
}
}

#defmt
#impl_defmt
});
} else {
let variants: BTreeMap<_, _> = e.variants.iter().map(|v| (v.value, v)).collect();
Expand All @@ -125,17 +124,13 @@ pub fn render(opts: &super::Options, _ir: &IR, e: &Enum, path: &str) -> Result<T
}
}

let defmt = opts.defmt_feature.as_ref().map(|defmt_feature| {
quote! {
#[cfg_attr(feature = #defmt_feature, derive(defmt::Format))]
}
});
let derive_defmt = with_defmt_cfg_attr(&opts.defmt, quote! { derive(defmt::Format) });

out.extend(quote! {
#doc
#[repr(#ty)]
#[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd)]
#defmt
#derive_defmt
pub enum #name {
#items
}
Expand Down
7 changes: 3 additions & 4 deletions src/generate/fieldset.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use quote::quote;
use crate::ir::*;
use crate::util;

use super::sorted;
use super::{sorted, with_defmt_cfg};

pub fn render(opts: &super::Options, ir: &IR, fs: &FieldSet, path: &str) -> Result<TokenStream> {
let span = Span::call_site();
Expand Down Expand Up @@ -190,7 +190,7 @@ pub fn render(opts: &super::Options, ir: &IR, fs: &FieldSet, path: &str) -> Resu
let name = Ident::new(name, span);
let doc = util::doc(&fs.description);

let impl_defmt_format = opts.defmt_feature.as_ref().map(|defmt_feature| {
let impl_defmt = with_defmt_cfg(&opts.defmt, || {
let mut defmt_format_string = String::new();
defmt_format_string.push_str(name_str);
defmt_format_string.push_str(" {{");
Expand All @@ -213,7 +213,6 @@ pub fn render(opts: &super::Options, ir: &IR, fs: &FieldSet, path: &str) -> Resu
defmt_format_string.push_str(" }}");

quote! {
#[cfg(feature = #defmt_feature)]
impl defmt::Format for #name {
fn format(&self, f: defmt::Formatter) {
defmt::write!(f, #defmt_format_string, #(#field_getters),*)
Expand Down Expand Up @@ -249,7 +248,7 @@ pub fn render(opts: &super::Options, ir: &IR, fs: &FieldSet, path: &str) -> Resu
}
}

#impl_defmt_format
#impl_defmt
};

Ok(out)
Expand Down
56 changes: 44 additions & 12 deletions src/generate/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,18 @@ pub enum CommonModule {
#[derive(Debug)]
pub struct Options {
common_module: CommonModule,
defmt_feature: Option<String>,
defmt: DefmtOption,
}

/// Option for generating code for `defmt` support.
#[derive(Debug, Clone)]
pub enum DefmtOption {
/// No code referencing `defmt` will be generated.
Disabled,
/// Support for `defmt` will be gated behind this feature.
Feature(String),
/// Support for `defmt` will be included unconditionally.
Enabled,
}

impl Default for Options {
Expand All @@ -89,7 +100,7 @@ impl Options {
pub fn new() -> Self {
Self {
common_module: CommonModule::Builtin,
defmt_feature: Some("defmt".into()),
defmt: DefmtOption::Feature("defmt".to_owned()),
}
}

Expand All @@ -115,19 +126,15 @@ impl Options {
self
}

/// Set the feature for adding defmt support in the generated code.
///
/// You can fully remove `defmt` support in the generated code by specifying `None`.
pub fn with_defmt_feature(mut self, defmt_feature: Option<String>) -> Self {
self.defmt_feature = defmt_feature;
/// Set the option for adding defmt support in the generated code.
pub fn with_defmt(mut self, defmt: DefmtOption) -> Self {
self.defmt = defmt;
self
}

/// Get the feature flag used to enable/disable `defmt` support in the generated code.
///
/// If set to `None`, no `defmt` support will be added at all to the generated code.
pub fn defmt_feature(&self) -> Option<&str> {
self.defmt_feature.as_deref()
/// Get the option for adding `defmt` support in the generated code.
pub fn defmt(&self) -> &DefmtOption {
&self.defmt
}
}

Expand Down Expand Up @@ -253,3 +260,28 @@ where
v.sort_by_key(|&(k, v)| by(k, v));
v
}

fn with_defmt_cfg<F>(defmt: &DefmtOption, f: F) -> Option<TokenStream>
where
F: FnOnce() -> TokenStream,
{
match defmt {
DefmtOption::Disabled => None,
DefmtOption::Feature(feature) => {
let body = f();
Some(quote! {
#[cfg(feature = #feature)]
#body
})
}
DefmtOption::Enabled => Some(f()),
}
}

fn with_defmt_cfg_attr(defmt: &DefmtOption, attr: TokenStream) -> Option<TokenStream> {
match defmt {
DefmtOption::Disabled => None,
DefmtOption::Feature(feature) => Some(quote! { #[cfg_attr(feature = #feature, #attr)] }),
DefmtOption::Enabled => Some(quote! { #[#attr] }),
}
}
75 changes: 45 additions & 30 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -80,19 +80,8 @@ struct Generate {
/// Transforms file path
#[clap(long)]
transform: Vec<String>,
/// Use an external `common` module.
#[clap(long)]
#[clap(value_name = "MODULE_PATH")]
common_module: Option<ModulePath>,
/// Specify the feature name used in the generated code to conditionally enable defmt support.
#[clap(long)]
#[clap(value_name = "FEATURE")]
#[clap(default_value = "defmt")]
#[clap(conflicts_with = "no_defmt")]
defmt_feature: String,
/// Do not add defmt support to the generated code at all.
#[clap(long)]
no_defmt: bool,
#[clap(flatten)]
gen_shared: GenShared,
}

/// Reformat a YAML
Expand Down Expand Up @@ -132,13 +121,33 @@ struct GenBlock {
/// Input YAML path
#[clap(short, long)]
input: String,
/// Output YAML path
/// Output Rust code path
#[clap(short, long)]
output: String,
#[clap(flatten)]
gen_shared: GenShared,
}

#[derive(Parser)]
struct GenShared {
/// Use an external `common` module.
#[clap(long)]
#[clap(value_name = "MODULE_PATH")]
common_module: Option<ModulePath>,
/// Specify the feature name used in the generated code to conditionally enable defmt support.
#[clap(long)]
#[clap(value_name = "FEATURE")]
#[clap(default_value = "defmt")]
#[clap(conflicts_with = "no_defmt")]
#[clap(conflicts_with = "yes_defmt")]
defmt_feature: String,
/// Do not add defmt support to the generated code at all.
#[clap(long)]
#[clap(conflicts_with = "yes_defmt")]
no_defmt: bool,
/// Add defmt support to the generated code unconditionally.
#[clap(long)]
yes_defmt: bool,
}

fn main() -> Result<()> {
Expand Down Expand Up @@ -273,17 +282,7 @@ fn gen(args: Generate) -> Result<()> {
apply_transform(&mut ir, transform)?;
}

let common_module = match args.common_module {
None => generate::CommonModule::Builtin,
Some(module) => generate::CommonModule::External(module.tokens()),
};
let defmt_feature = match args.no_defmt {
true => None,
false => Some(args.defmt_feature),
};
let generate_opts = generate::Options::default()
.with_common_module(common_module)
.with_defmt_feature(defmt_feature);
let generate_opts = get_generate_opts(args.gen_shared)?;
let items = generate::render(&ir, &generate_opts).unwrap();
fs::write("lib.rs", items.to_string())?;

Expand Down Expand Up @@ -404,16 +403,13 @@ fn gen_block(args: GenBlock) -> Result<()> {
// Ensure consistent sort order in the YAML.
chiptool::transform::sort::Sort {}.run(&mut ir).unwrap();

let common_module = match args.common_module {
None => generate::CommonModule::Builtin,
Some(module) => generate::CommonModule::External(module.tokens()),
};
let generate_opts = generate::Options::default().with_common_module(common_module);
let generate_opts = get_generate_opts(args.gen_shared)?;
let items = generate::render(&ir, &generate_opts).unwrap();
fs::write(&args.output, items.to_string())?;

Ok(())
}

#[derive(Default, serde::Serialize, serde::Deserialize)]
struct Config {
#[serde(default)]
Expand Down Expand Up @@ -478,3 +474,22 @@ impl std::str::FromStr for ModulePath {
Ok(Self { path: data.into() })
}
}

fn get_generate_opts(args: GenShared) -> Result<generate::Options> {
let common_module = match args.common_module {
None => generate::CommonModule::Builtin,
Some(module) => generate::CommonModule::External(module.tokens()),
};

let defmt = match (args.no_defmt, args.yes_defmt) {
(true, false) => generate::DefmtOption::Disabled,
(false, true) => generate::DefmtOption::Enabled,
(false, false) => generate::DefmtOption::Feature(args.defmt_feature),
(true, true) => bail!("--no-defmt and --yes-defmt are mutually exclusive"),
};

let opts = generate::Options::default()
.with_common_module(common_module)
.with_defmt(defmt);
Ok(opts)
}