Skip to content

Commit

Permalink
Merge pull request #769 from rust-embedded/config
Browse files Browse the repository at this point in the history
mode Config to config module
  • Loading branch information
Emilgardis authored Nov 23, 2023
2 parents 2fd1d1f + 8e2d1b9 commit f6d0cb0
Show file tree
Hide file tree
Showing 8 changed files with 124 additions and 163 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/).
Add `width`, `offset` methods
- *breaking change* Always numerates field arrays from 0
- Support of default value for `EnumeratedValues`
- move `Config` to `config` module

## [v0.30.3] - 2023-11-19

Expand Down
98 changes: 98 additions & 0 deletions src/config.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
use anyhow::{bail, Result};
use std::path::{Path, PathBuf};

#[cfg_attr(feature = "serde", derive(serde::Deserialize))]
#[derive(Clone, PartialEq, Eq, Debug, Default)]
#[cfg_attr(feature = "serde", serde(default))]
pub struct Config {
pub target: Target,
pub atomics: bool,
pub atomics_feature: Option<String>,
pub generic_mod: bool,
pub make_mod: bool,
pub ignore_groups: bool,
pub keep_list: bool,
pub strict: bool,
pub pascal_enum_values: bool,
pub feature_group: bool,
pub feature_peripheral: bool,
pub max_cluster_size: bool,
pub impl_debug: bool,
pub impl_debug_feature: Option<String>,
pub output_dir: Option<PathBuf>,
pub input: Option<PathBuf>,
pub source_type: SourceType,
pub log_level: Option<String>,
pub interrupt_link_section: Option<String>,
pub reexport_core_peripherals: bool,
pub reexport_interrupt: bool,
}

#[allow(clippy::upper_case_acronyms)]
#[allow(non_camel_case_types)]
#[cfg_attr(feature = "serde", derive(serde::Deserialize))]
#[derive(Clone, Copy, PartialEq, Eq, Debug, Default)]
pub enum Target {
#[cfg_attr(feature = "serde", serde(rename = "cortex-m"))]
#[default]
CortexM,
#[cfg_attr(feature = "serde", serde(rename = "msp430"))]
Msp430,
#[cfg_attr(feature = "serde", serde(rename = "riscv"))]
RISCV,
#[cfg_attr(feature = "serde", serde(rename = "xtensa-lx"))]
XtensaLX,
#[cfg_attr(feature = "serde", serde(rename = "mips"))]
Mips,
#[cfg_attr(feature = "serde", serde(rename = "none"))]
None,
}

impl Target {
pub fn parse(s: &str) -> Result<Self> {
Ok(match s {
"cortex-m" => Target::CortexM,
"msp430" => Target::Msp430,
"riscv" => Target::RISCV,
"xtensa-lx" => Target::XtensaLX,
"mips" => Target::Mips,
"none" => Target::None,
_ => bail!("unknown target {}", s),
})
}
}

#[cfg_attr(
feature = "serde",
derive(serde::Deserialize),
serde(rename_all = "lowercase")
)]
#[derive(Clone, Copy, PartialEq, Eq, Debug, Default)]
pub enum SourceType {
#[default]
Xml,
#[cfg(feature = "yaml")]
Yaml,
#[cfg(feature = "json")]
Json,
}

impl SourceType {
/// Make a new [`SourceType`] from a given extension.
pub fn from_extension(s: &str) -> Option<Self> {
match s {
"svd" | "xml" => Some(Self::Xml),
#[cfg(feature = "yaml")]
"yml" | "yaml" => Some(Self::Yaml),
#[cfg(feature = "json")]
"json" => Some(Self::Json),
_ => None,
}
}
pub fn from_path(path: &Path) -> Self {
path.extension()
.and_then(|e| e.to_str())
.and_then(Self::from_extension)
.unwrap_or_default()
}
}
13 changes: 10 additions & 3 deletions src/generate/device.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,10 @@ use log::debug;
use std::borrow::Cow;
use std::fs::File;
use std::io::Write;
use std::path::Path;

use crate::util::{self, Config, ToSanitizedCase};
use crate::Target;
use crate::config::{Config, Target};
use crate::util::{self, ToSanitizedCase};
use anyhow::{Context, Result};

use crate::generate::{interrupt, peripheral};
Expand Down Expand Up @@ -139,7 +140,13 @@ pub fn render(d: &Device, config: &Config, device_x: &mut String) -> Result<Toke
let generic_file = include_str!("generic.rs");
let generic_atomic_file = include_str!("generic_atomic.rs");
if config.generic_mod {
let mut file = File::create(config.output_dir.join("generic.rs"))?;
let mut file = File::create(
config
.output_dir
.as_deref()
.unwrap_or(Path::new("."))
.join("generic.rs"),
)?;
writeln!(file, "{generic_file}")?;
if config.atomics {
if let Some(atomics_feature) = config.atomics_feature.as_ref() {
Expand Down
5 changes: 3 additions & 2 deletions src/generate/peripheral.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ use svd_parser::expand::{
derive_cluster, derive_peripheral, derive_register, BlockPath, Index, RegisterPath,
};

use crate::config::Config;
use crate::svd::{
self, Cluster, ClusterInfo, MaybeArray, Peripheral, Register, RegisterCluster, RegisterInfo,
};
Expand All @@ -15,8 +16,8 @@ use quote::{quote, ToTokens};
use syn::{punctuated::Punctuated, Token};

use crate::util::{
self, name_to_ty, path_segment, type_path, unsuffixed, zst_type, Config, FullName,
ToSanitizedCase, BITS_PER_BYTE,
self, name_to_ty, path_segment, type_path, unsuffixed, zst_type, FullName, ToSanitizedCase,
BITS_PER_BYTE,
};
use anyhow::{anyhow, bail, Context, Result};

Expand Down
3 changes: 2 additions & 1 deletion src/generate/register.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,9 @@ use svd_parser::expand::{
derive_enumerated_values, derive_field, BlockPath, EnumPath, FieldPath, Index, RegisterPath,
};

use crate::config::Config;
use crate::util::{
self, ident_to_path, path_segment, replace_suffix, type_path, unsuffixed, Config, FullName,
self, ident_to_path, path_segment, replace_suffix, type_path, unsuffixed, FullName,
ToSanitizedCase, U32Ext,
};
use anyhow::{anyhow, Result};
Expand Down
9 changes: 5 additions & 4 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -538,10 +538,11 @@
use quote::quote;
use svd_parser::svd;

pub mod config;
pub mod generate;
pub mod util;

pub use crate::util::{Config, Target};
pub use config::{Config, Target};

#[non_exhaustive]
pub struct Generation {
Expand Down Expand Up @@ -599,9 +600,9 @@ pub fn generate(input: &str, config: &Config) -> Result<Generation> {
})
}

/// Load a [Device](svd::Device) from a string slice with given [config](crate::util::Config).
pub fn load_from(input: &str, config: &crate::util::Config) -> Result<svd::Device> {
use self::util::SourceType;
/// Load a [Device](svd::Device) from a string slice with given [config](crate::config::Config).
pub fn load_from(input: &str, config: &Config) -> Result<svd::Device> {
use config::SourceType;
use svd_parser::ValidateLevel;

let mut device = match config.source_type {
Expand Down
7 changes: 4 additions & 3 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,17 @@

use log::{debug, error, info};

use std::fs::File;
use std::io::Write;
use std::process;
use std::{fs::File, path::Path};

use anyhow::{Context, Result};
use clap::{Arg, ArgAction, Command};

use svd2rust::{
config::{Config, SourceType, Target},
generate, load_from,
util::{self, build_rs, Config, SourceType, Target},
util::{self, build_rs},
};

fn parse_configs(app: Command) -> Result<Config> {
Expand Down Expand Up @@ -216,7 +217,7 @@ fn run() -> Result<()> {
if let Some(file) = config.input.as_ref() {
config.source_type = SourceType::from_path(file)
}
let path = &config.output_dir;
let path = config.output_dir.as_deref().unwrap_or(Path::new("."));

info!("Parsing device from SVD file");
let device = load_from(input, &config)?;
Expand Down
151 changes: 1 addition & 150 deletions src/util.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,68 +6,20 @@ use inflections::Inflect;
use proc_macro2::{Ident, Span, TokenStream};
use quote::quote;
use std::collections::HashSet;
use std::path::{Path, PathBuf};
use svd_rs::{MaybeArray, Peripheral, PeripheralInfo};

use syn::{
punctuated::Punctuated, token::PathSep, Lit, LitInt, PathArguments, PathSegment, Type, TypePath,
};

use anyhow::{anyhow, bail, Result};
use anyhow::{anyhow, Result};

pub const BITS_PER_BYTE: u32 = 8;

/// List of chars that some vendors use in their peripheral/field names but
/// that are not valid in Rust ident
const BLACKLIST_CHARS: &[char] = &['(', ')', '[', ']', '/', ' ', '-'];

#[cfg_attr(feature = "serde", derive(serde::Deserialize))]
#[derive(Clone, PartialEq, Eq, Debug)]
pub struct Config {
#[cfg_attr(feature = "serde", serde(default))]
pub target: Target,
#[cfg_attr(feature = "serde", serde(default))]
pub atomics: bool,
#[cfg_attr(feature = "serde", serde(default))]
pub atomics_feature: Option<String>,
#[cfg_attr(feature = "serde", serde(default))]
pub generic_mod: bool,
#[cfg_attr(feature = "serde", serde(default))]
pub make_mod: bool,
#[cfg_attr(feature = "serde", serde(default))]
pub ignore_groups: bool,
#[cfg_attr(feature = "serde", serde(default))]
pub keep_list: bool,
#[cfg_attr(feature = "serde", serde(default))]
pub strict: bool,
#[cfg_attr(feature = "serde", serde(default))]
pub pascal_enum_values: bool,
#[cfg_attr(feature = "serde", serde(default))]
pub feature_group: bool,
#[cfg_attr(feature = "serde", serde(default))]
pub feature_peripheral: bool,
#[cfg_attr(feature = "serde", serde(default))]
pub max_cluster_size: bool,
#[cfg_attr(feature = "serde", serde(default))]
pub impl_debug: bool,
#[cfg_attr(feature = "serde", serde(default))]
pub impl_debug_feature: Option<String>,
#[cfg_attr(feature = "serde", serde(default = "current_dir"))]
pub output_dir: PathBuf,
#[cfg_attr(feature = "serde", serde(default))]
pub input: Option<PathBuf>,
#[cfg_attr(feature = "serde", serde(default))]
pub source_type: SourceType,
#[cfg_attr(feature = "serde", serde(default))]
pub log_level: Option<String>,
#[cfg_attr(feature = "serde", serde(default))]
pub interrupt_link_section: Option<String>,
#[cfg_attr(feature = "serde", serde(default))]
pub reexport_core_peripherals: bool,
#[cfg_attr(feature = "serde", serde(default))]
pub reexport_interrupt: bool,
}

#[derive(Clone, Debug, PartialEq, Eq)]
pub enum Case {
Constant,
Expand Down Expand Up @@ -103,107 +55,6 @@ impl Case {
}
}

fn current_dir() -> PathBuf {
PathBuf::from(".")
}

impl Default for Config {
fn default() -> Self {
Self {
target: Target::default(),
atomics: false,
atomics_feature: None,
generic_mod: false,
make_mod: false,
ignore_groups: false,
keep_list: false,
strict: false,
pascal_enum_values: false,
feature_group: false,
feature_peripheral: false,
max_cluster_size: false,
impl_debug: false,
impl_debug_feature: None,
output_dir: current_dir(),
input: None,
source_type: SourceType::default(),
log_level: None,
interrupt_link_section: None,
reexport_core_peripherals: false,
reexport_interrupt: false,
}
}
}

#[allow(clippy::upper_case_acronyms)]
#[allow(non_camel_case_types)]
#[cfg_attr(feature = "serde", derive(serde::Deserialize))]
#[derive(Clone, Copy, PartialEq, Eq, Debug, Default)]
pub enum Target {
#[cfg_attr(feature = "serde", serde(rename = "cortex-m"))]
#[default]
CortexM,
#[cfg_attr(feature = "serde", serde(rename = "msp430"))]
Msp430,
#[cfg_attr(feature = "serde", serde(rename = "riscv"))]
RISCV,
#[cfg_attr(feature = "serde", serde(rename = "xtensa-lx"))]
XtensaLX,
#[cfg_attr(feature = "serde", serde(rename = "mips"))]
Mips,
#[cfg_attr(feature = "serde", serde(rename = "none"))]
None,
}

impl Target {
pub fn parse(s: &str) -> Result<Self> {
Ok(match s {
"cortex-m" => Target::CortexM,
"msp430" => Target::Msp430,
"riscv" => Target::RISCV,
"xtensa-lx" => Target::XtensaLX,
"mips" => Target::Mips,
"none" => Target::None,
_ => bail!("unknown target {}", s),
})
}
}

#[cfg_attr(
feature = "serde",
derive(serde::Deserialize),
serde(rename_all = "lowercase")
)]
#[derive(Clone, Copy, PartialEq, Eq, Debug, Default)]
pub enum SourceType {
#[default]
Xml,
#[cfg(feature = "yaml")]
Yaml,
#[cfg(feature = "json")]
Json,
}

impl SourceType {
/// Make a new [`SourceType`] from a given extension.
pub fn from_extension(s: &str) -> Option<Self> {
match s {
"svd" | "xml" => Some(Self::Xml),
#[cfg(feature = "yaml")]
"yml" | "yaml" => Some(Self::Yaml),
#[cfg(feature = "json")]
"json" => Some(Self::Json),
_ => None,
}
}
pub fn from_path(path: &Path) -> Self {
path.extension()
.and_then(|e| e.to_str())
.and_then(Self::from_extension)
.unwrap_or_default()
}
}

/// Convert self string into specific case without overlapping to svd2rust internal names
pub trait ToSanitizedCase {
/// Convert self into PascalCase.
Expand Down

0 comments on commit f6d0cb0

Please sign in to comment.