use std::fmt;
use std::result;
pub struct SymConfig {}
pub struct ModConfig {
pub font_size: f64,
pub font_thickness: f64,
}
pub struct Config {
pub name: String,
pub s: SymConfig,
pub m: ModConfig,
}
impl Config {
pub fn klc() -> Config {
Config {
name: "KLC 2.0.10".into(),
s: SymConfig {},
m: ModConfig {
font_size: 1.0,
font_thickness: 0.15,
},
}
}
}
pub trait CheckFix {
fn check(&self, config: &Config) -> Vec<CheckFixData>;
fn fix(&mut self, _config: &Config) {}
}
#[derive(Debug)]
pub enum CheckFixData {
Item(CheckFixItem),
More(Vec<CheckFixData>),
}
impl CheckFixData {
pub fn flatter(self) -> Self {
match self {
CheckFixData::Item(_) => self,
CheckFixData::More(v) => if v.len() == 1 {
v.into_iter().next().unwrap()
} else {
CheckFixData::More(v)
},
}
}
pub fn new<A: fmt::Display, B: Into<String>>(
section: i64,
rule: i64,
item: A,
message: B,
) -> Self {
let i = CheckFixItem::new(section, rule, item, message.into());
CheckFixData::Item(i)
}
pub fn info<A: fmt::Display, B: Into<String>>(
section: i64,
rule: i64,
item: A,
message: B,
) -> Self {
let i = CheckFixItem::new(section, rule, item, message.into()).info();
CheckFixData::Item(i)
}
pub fn dump_on_logger(&self, indent: usize) {
match *self {
CheckFixData::Item(ref item) => item.dump_on_logger(indent),
CheckFixData::More(ref more) => for klcdata in more {
let new_indent = match *klcdata {
CheckFixData::Item(_) => indent,
CheckFixData::More(_) => indent + 1,
};
klcdata.dump_on_logger(new_indent)
},
}
}
}
#[derive(Debug)]
pub struct CheckFixItem {
pub section: i64,
pub rule: i64,
pub item: String,
pub message: String,
pub info: bool,
}
impl CheckFixItem {
pub fn new<A: fmt::Display, B: Into<String>>(
section: i64,
rule: i64,
item: A,
message: B,
) -> Self {
CheckFixItem {
section: section,
rule: rule,
item: format!("{}", item),
message: message.into(),
info: false,
}
}
pub fn info(self) -> CheckFixItem {
CheckFixItem { info: true, ..self }
}
pub fn dump_on_logger(&self, indent: usize) {
let indent = ::std::iter::repeat(" ")
.take(indent * 2)
.collect::<String>();
if self.info {
info!(
"{}{}.{} {}:{}",
indent,
self.section,
self.rule,
self.item,
self.message
)
} else {
warn!(
"{}{}.{} {}:{}",
indent,
self.section,
self.rule,
self.item,
self.message
)
}
}
}
#[derive(Debug)]
pub enum KLCSection {
General,
SymbolLibraryNames,
SymbolNames,
SymbolRules,
FootprintLibraryNames,
FootprintNames,
FootprintRules,
SMDRules,
THTRules,
FootprintProperties,
}
impl Into<i64> for KLCSection {
fn into(self) -> i64 {
match self {
KLCSection::General => 1,
KLCSection::SymbolLibraryNames => 2,
KLCSection::SymbolNames => 3,
KLCSection::SymbolRules => 4,
KLCSection::FootprintLibraryNames => 5,
KLCSection::FootprintNames => 6,
KLCSection::FootprintRules => 7,
KLCSection::SMDRules => 8,
KLCSection::THTRules => 9,
KLCSection::FootprintProperties => 10,
}
}
}
impl fmt::Display for KLCSection {
fn fmt(&self, f: &mut fmt::Formatter) -> result::Result<(), fmt::Error> {
let s = match *self {
KLCSection::General => "General Rules",
KLCSection::SymbolLibraryNames => "Symbol Library Names",
KLCSection::SymbolNames => "Symbol Names",
KLCSection::SymbolRules => "General Rules for Symbols",
KLCSection::FootprintLibraryNames => "Footprint Library Names",
KLCSection::FootprintNames => "Footprint Names",
KLCSection::FootprintRules => "General Rules for Footprints",
KLCSection::SMDRules => "Rules for SMD Footprints",
KLCSection::THTRules => "Rules for Through-hole Footprints",
KLCSection::FootprintProperties => "Footprint Properties",
};
write!(f, "{}", s)
}
}
const ALLOWED_1_7: &'static str = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_-.";
fn allowed_1_7(s: &str) -> Option<Vec<String>> {
let mut v = vec![];
for (i, c) in s.chars().enumerate() {
if ALLOWED_1_7.chars().find(|&x| x == c).is_none() {
v.push(format!("Invalid char '{}' at {} in '{}'", c, i, s))
}
}
if v.is_empty() {
None
} else {
Some(v)
}
}
pub fn allowed_1_7_items(s: &str) -> Vec<CheckFixData> {
let mut v = vec![];
if let Some(v2) = allowed_1_7(s) {
for x in v2 {
v.push(CheckFixData::new(1, 7, s, x))
}
}
v
}
pub fn is_allowed_1_7(s: &str) -> bool {
allowed_1_7(s).is_none()
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_allowed_1_7_1() {
assert!(allowed_1_7("Hello_world_1.23-4").is_none())
}
#[test]
fn test_allowed_1_7_2() {
let t = allowed_1_7("Hello world")
.unwrap()
.into_iter()
.next()
.unwrap();
assert_eq!(t, "Invalid char ' ' at 5 in 'Hello world'")
}
}