diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..39a5ca1 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,3 @@ +{ + "rust-analyzer.cargo.features": "all" +} diff --git a/Cargo.lock b/Cargo.lock index 245ca76..a5546ec 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -45,21 +45,23 @@ dependencies = [ [[package]] name = "kicad_format" -version = "0.1.0" +version = "0.1.1" dependencies = [ "ansi_term", "diff", "kicad_sexpr", "regex", + "serde", "thiserror", "uuid", ] [[package]] name = "kicad_sexpr" -version = "0.1.0" +version = "0.1.1" dependencies = [ "nom", + "serde", "thiserror", ] @@ -174,6 +176,26 @@ version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f" +[[package]] +name = "serde" +version = "1.0.203" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7253ab4de971e72fb7be983802300c30b5a7f0c2e56fab8abfc6a214307c0094" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.203" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "500cbc0ebeb6f46627f50f3f5811ccf6bf00643be300b4c3eabc0ef55dc5b5ba" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "syn" version = "2.0.48" @@ -213,12 +235,13 @@ checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" [[package]] name = "uuid" -version = "1.7.0" +version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f00cc9702ca12d3c81455259621e676d0f7251cec66a21e98fe2e9a37db93b2a" +checksum = "a183cf7feeba97b4dd1c0d46788634f6221d87fa961b305bed08c851829efcc0" dependencies = [ "getrandom", "rand", + "serde", ] [[package]] diff --git a/kicad_format/Cargo.toml b/kicad_format/Cargo.toml index 0a17cb9..d13ca53 100644 --- a/kicad_format/Cargo.toml +++ b/kicad_format/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "kicad_format" -version = "0.1.0" +version = "0.1.1" edition = "2021" description = "A library for parsing KiCad 7.10 files into a more data driven representation" authors = ["Adrian Wowk "] @@ -9,9 +9,15 @@ license = "MIT" [dependencies] kicad_sexpr = { path = "../kicad_sexpr" } regex = "1.10.3" +serde = { version = "1.0.130", features = ["derive"], optional = true } thiserror = "1.0.56" -uuid = { version = "1.7.0", features = ["v4", "fast-rng"] } +uuid = { version = "1.8.0", features = ["v4", "fast-rng"] } + [dev-dependencies] ansi_term = "0.12.1" diff = "0.1.13" + + +[features] +serde = ["dep:serde", "uuid/serde"] diff --git a/kicad_format/src/common/footprint/mod.rs b/kicad_format/src/common/footprint/mod.rs index f81749a..6afd264 100644 --- a/kicad_format/src/common/footprint/mod.rs +++ b/kicad_format/src/common/footprint/mod.rs @@ -26,6 +26,8 @@ pub mod text; /// A footprint inlined within a PCB file. /// /// TODO: move to pcb module +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr(feature = "serde", serde(rename_all = "snake_case"))] #[derive(Debug, PartialEq, Clone)] pub struct FootprintInlined { pub library_link: LibraryId, @@ -299,6 +301,8 @@ impl ToSexpr for FootprintInlined { // ############################################################################ /// How pads are covered by copper in Zone +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr(feature = "serde", serde(rename_all = "snake_case"))] #[derive(Debug, PartialEq, Clone, Copy)] #[repr(u8)] pub enum ZoneConnectKind { @@ -331,6 +335,8 @@ impl TryFrom for ZoneConnectKind { // ############################################################################ /// Attributes of the footprint (ex. SMD, through-hole, included in BOM, etc.) +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr(feature = "serde", serde(rename_all = "snake_case"))] #[derive(Debug, PartialEq, Default, Clone)] pub struct FootprintAttributes { pub smd: bool, @@ -395,6 +401,9 @@ impl ToSexpr for FootprintAttributes { /// All the types of graphics items that can be part of a footprint (images, /// text, text boxes, shapes, etc.) +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr(feature = "serde", serde(rename_all = "snake_case"))] +#[cfg_attr(feature = "serde", serde(tag = "type"))] #[derive(Debug, PartialEq, Clone)] pub enum FootprintGraphicsItem { Image(Image), @@ -462,6 +471,8 @@ impl ToSexpr for FootprintGraphicsItem { // ############################################################################ /// A 3D model associated with a footprint. +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr(feature = "serde", serde(rename_all = "snake_case"))] #[derive(Debug, PartialEq, Clone)] pub struct Model { pub file: String, diff --git a/kicad_format/src/common/footprint/shape.rs b/kicad_format/src/common/footprint/shape.rs index 949f75e..3f82e6c 100644 --- a/kicad_format/src/common/footprint/shape.rs +++ b/kicad_format/src/common/footprint/shape.rs @@ -9,6 +9,8 @@ use crate::{ }; /// Common properties shared by the different shapes. +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr(feature = "serde", serde(rename_all = "snake_case"))] #[derive(Debug, PartialEq, Clone)] pub struct FootprintShape { pub locked: bool, @@ -19,6 +21,9 @@ pub struct FootprintShape { } /// All the different types of shapes allowed within a footprint. +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr(feature = "serde", serde(rename_all = "snake_case"))] +#[cfg_attr(feature = "serde", serde(tag = "type"))] #[derive(Debug, PartialEq, Clone)] pub enum FootprintShapeKind { Line(FootprintLine), @@ -221,12 +226,16 @@ impl ToSexpr for FootprintShape { } } +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr(feature = "serde", serde(rename_all = "snake_case"))] #[derive(Debug, PartialEq, Clone)] pub struct FootprintLine { pub start: Vec2D, pub end: Vec2D, } +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr(feature = "serde", serde(rename_all = "snake_case"))] #[derive(Debug, PartialEq, Clone)] pub struct FootprintRectangle { pub start: Vec2D, @@ -234,6 +243,8 @@ pub struct FootprintRectangle { pub fill: SimpleFillMode, } +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr(feature = "serde", serde(rename_all = "snake_case"))] #[derive(Debug, PartialEq, Clone)] pub struct FootprintCircle { pub center: Vec2D, @@ -241,6 +252,8 @@ pub struct FootprintCircle { pub fill: SimpleFillMode, } +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr(feature = "serde", serde(rename_all = "snake_case"))] #[derive(Debug, PartialEq, Clone)] pub struct FootprintArc { pub start: Vec2D, @@ -248,12 +261,16 @@ pub struct FootprintArc { pub end: Vec2D, } +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr(feature = "serde", serde(rename_all = "snake_case"))] #[derive(Debug, PartialEq, Clone)] pub struct FootprintPolygon { pub points: CoordinatePointList, pub fill: SimpleFillMode, } +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr(feature = "serde", serde(rename_all = "snake_case"))] #[derive(Debug, PartialEq, Clone)] pub struct FootprintBezier { pub points: [Vec2D; 4], diff --git a/kicad_format/src/common/footprint/text.rs b/kicad_format/src/common/footprint/text.rs index 2270984..b62fdc0 100644 --- a/kicad_format/src/common/footprint/text.rs +++ b/kicad_format/src/common/footprint/text.rs @@ -9,6 +9,8 @@ use crate::{ }; /// A footprint text element. +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr(feature = "serde", serde(rename_all = "snake_case"))] #[derive(Debug, PartialEq, Clone)] pub struct FootprintText { pub kind: FootprintTextKind, @@ -81,6 +83,8 @@ impl ToSexpr for FootprintText { /// /// Reference and value always live on silkscreen (on the footprint side); /// other texts are planned to go on whatever layer the user wants. +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr(feature = "serde", serde(rename_all = "snake_case"))] #[derive(Debug, PartialEq, Clone, Copy)] pub enum FootprintTextKind { Reference, @@ -97,6 +101,8 @@ simple_to_from_string! { /// An extension of the normal [`Position`](crate::common::Position) struct that includes an `unlocked` /// field +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr(feature = "serde", serde(rename_all = "snake_case"))] #[derive(Debug, PartialEq, Clone)] pub struct FootprintTextPosition { pub x: f32, @@ -140,6 +146,8 @@ impl ToSexpr for FootprintTextPosition { // FIXME: Really should be an enum because there are 2 valid types of text boxes // (axis aligned and partially rotated) /// A footprint text box element. +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr(feature = "serde", serde(rename_all = "snake_case"))] #[derive(Debug, PartialEq, Clone)] pub struct FootprintTextBox { pub locked: bool, diff --git a/kicad_format/src/common/mod.rs b/kicad_format/src/common/mod.rs index e5c6af8..45545bb 100644 --- a/kicad_format/src/common/mod.rs +++ b/kicad_format/src/common/mod.rs @@ -19,6 +19,8 @@ pub mod symbol; pub mod zone; /// Generic position type used in many parts of the format. +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr(feature = "serde", serde(rename_all = "snake_case"))] #[derive(Debug, PartialEq, Clone)] pub struct Position { /// The `X` attribute defines the horizontal position of the object. @@ -87,6 +89,8 @@ impl ToSexpr for CoordinatePointList { } /// A single coordinate pair +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr(feature = "serde", serde(rename_all = "snake_case"))] #[derive(Debug, PartialEq, Clone)] pub struct Vec2D { pub x: f32, @@ -144,6 +148,8 @@ impl ToSexprWithName for Vec2D { // ############################################################################ /// A single 3D coordinate pair +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr(feature = "serde", serde(rename_all = "snake_case"))] #[derive(Debug, PartialEq, Clone)] pub struct Vec3D { pub x: f32, @@ -196,6 +202,8 @@ impl ToSexprWithName for Vec3D { /// /// Used for various graphical objects such as lines, arcs, circles, polygons, /// and text. +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr(feature = "serde", serde(rename_all = "snake_case"))] #[derive(Debug, PartialEq, Default, Clone)] pub struct Stroke { /// The `width` token attribute defines the line width of the graphic object. @@ -260,6 +268,8 @@ impl ToSexpr for Stroke { } /// Defines the possible stroke line styles. +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr(feature = "serde", serde(rename_all = "snake_case"))] #[derive(Debug, PartialEq, Clone, Copy, Default)] pub enum StrokeKind { #[default] @@ -282,6 +292,8 @@ simple_to_from_string! { } /// An RGBA color +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr(feature = "serde", serde(rename_all = "snake_case"))] #[derive(Debug, PartialEq, Clone)] pub struct Color { pub red: u8, @@ -330,6 +342,8 @@ impl ToSexpr for Color { /// All text objects can have an optional effects section that defines how the /// text is displayed. +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr(feature = "serde", serde(rename_all = "snake_case"))] #[derive(Debug, PartialEq, Clone)] pub struct TextEffects { /// The `font` token attributes define how the text is shown. @@ -415,6 +429,8 @@ impl ToSexpr for TextEffects { } /// A font definition for text objects. +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr(feature = "serde", serde(rename_all = "snake_case"))] #[derive(Debug, PartialEq, Clone)] pub struct Font { /// The optional face token indicates the font family. It should be a @@ -484,6 +500,8 @@ impl ToSexpr for Font { } /// Text justification options. +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr(feature = "serde", serde(rename_all = "snake_case"))] #[derive(Debug, PartialEq, Clone)] pub struct Justify { pub horizontal_direction: Option, @@ -530,6 +548,8 @@ impl ToSexpr for Justify { } /// See the `horizontal_direction` field in [`Justify`]. +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr(feature = "serde", serde(rename_all = "snake_case"))] #[derive(Debug, PartialEq, Clone, Copy)] pub enum HorizontalDirection { Left, @@ -543,6 +563,8 @@ simple_to_from_string! { } /// See the `vertical_direction` field in [`Justify`]. +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr(feature = "serde", serde(rename_all = "snake_case"))] #[derive(Debug, PartialEq, Clone, Copy)] pub enum VerticalDirection { Top, @@ -558,6 +580,8 @@ simple_to_from_string! { // ############################################################################ /// Defines the drawing page size and orientation. +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr(feature = "serde", serde(rename_all = "snake_case"))] #[derive(Debug, PartialEq, Clone)] pub struct PageSettings { pub size: PageSize, @@ -611,6 +635,9 @@ impl ToSexpr for PageSettings { } /// The page size definition can either be a standard size or a custom size. +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr(feature = "serde", serde(rename_all = "snake_case"))] +#[cfg_attr(feature = "serde", serde(tag = "type"))] #[derive(Debug, PartialEq, Clone)] pub enum PageSize { Standard(StandardPageSize), @@ -618,6 +645,8 @@ pub enum PageSize { } /// All the preset standard page sizes +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr(feature = "serde", serde(rename_all = "snake_case"))] #[derive(Debug, PartialEq, Clone, Copy)] pub enum StandardPageSize { A0, @@ -657,6 +686,8 @@ simple_to_from_string! { } /// A custom page size definition. +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr(feature = "serde", serde(rename_all = "snake_case"))] #[derive(Debug, PartialEq, Clone)] pub struct CustomPageSize { pub width: f32, @@ -666,6 +697,8 @@ pub struct CustomPageSize { // ############################################################################ /// Title block information displayed in the corner of the page +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr(feature = "serde", serde(rename_all = "snake_case"))] #[derive(Debug, PartialEq, Clone)] pub struct TitleBlock { /// The `title` token attribute is a quoted string that defines the @@ -736,6 +769,8 @@ impl ToSexpr for TitleBlock { } /// A comment within the [`TitleBlock`]. +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr(feature = "serde", serde(rename_all = "snake_case"))] #[derive(Debug, PartialEq, Clone)] pub struct Comment { pub index: u8, @@ -772,6 +807,8 @@ impl ToSexpr for Comment { // ############################################################################ /// A generic property key-value pair. +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr(feature = "serde", serde(rename_all = "snake_case"))] #[derive(Debug, PartialEq, Clone)] pub struct Property { /// The property key attribute is a string that defines the name of the @@ -813,6 +850,8 @@ impl ToSexpr for Property { /// although that is an artifact of the legacy file format). /// /// TODO: replace with just uuid::Uuid +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr(feature = "serde", serde(rename_all = "snake_case"))] #[derive(Debug, PartialEq, Clone)] pub struct Uuid( /// The UUID attribute is a Version 4 (random) UUID that should be globally @@ -822,6 +861,7 @@ pub struct Uuid( /// /// Files converted from legacy versions of KiCad (prior to 6.0) have their /// locally-unique timestamps re-encoded in UUID format. + #[cfg_attr(feature = "serde", serde(with = "uuid::serde::simple"))] pub uuid::Uuid, ); @@ -891,6 +931,8 @@ impl From for uuid::Uuid { // ############################################################################ /// An embedded bitmap image stored in Base64 encoded PNG format. +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr(feature = "serde", serde(rename_all = "snake_case"))] #[derive(Debug, PartialEq, Clone)] pub struct Image { /// The POSITION_IDENTIFIER defines the X and Y coordinates of the image. @@ -969,6 +1011,9 @@ impl ToSexpr for Image { /// the wildcard. For instance, *.Cu represents all of the copper layers. This /// only applies to canonical layers names. #[repr(u8)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr(feature = "serde", serde(rename_all = "snake_case"))] +#[cfg_attr(feature = "serde", serde(tag = "type"))] #[derive(Debug, PartialEq, Clone, Copy)] pub enum LayerId { FCu, @@ -1236,6 +1281,8 @@ impl From for String { // ############################################################################ /// A group of items represented by a list of unique identifiers. +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr(feature = "serde", serde(rename_all = "snake_case"))] #[derive(Debug, PartialEq, Clone)] pub struct Group { /// The name attribute defines the name of the group. @@ -1309,6 +1356,8 @@ impl ToSexpr for Group { // ############################################################################ /// The fill mode used by most solid shapes +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr(feature = "serde", serde(rename_all = "snake_case"))] #[derive(Debug, PartialEq, Clone, Copy)] pub enum SimpleFillMode { Solid, diff --git a/kicad_format/src/common/pad/mod.rs b/kicad_format/src/common/pad/mod.rs index 8a5c267..1b6a851 100644 --- a/kicad_format/src/common/pad/mod.rs +++ b/kicad_format/src/common/pad/mod.rs @@ -14,6 +14,8 @@ use crate::{ pub mod primitive; /// A footprint pad +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr(feature = "serde", serde(rename_all = "snake_case"))] #[derive(Debug, PartialEq, Clone)] pub struct Pad { pub index: String, @@ -256,6 +258,8 @@ impl ToSexpr for Pad { } } +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr(feature = "serde", serde(rename_all = "snake_case"))] #[derive(Debug, PartialEq, Clone, Copy)] pub enum PadKind { ThroughHole, @@ -272,6 +276,8 @@ simple_to_from_string! { np_thru_hole <-> NpThroughHole, } +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr(feature = "serde", serde(rename_all = "snake_case"))] #[derive(Debug, PartialEq, Clone, Copy)] pub enum PadShape { Circle, @@ -292,6 +298,8 @@ simple_to_from_string! { custom <-> Custom, } +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr(feature = "serde", serde(rename_all = "snake_case"))] #[derive(Debug, PartialEq, Clone)] pub struct Drill { pub diameter: f32, @@ -342,6 +350,8 @@ impl ToSexpr for Drill { } } +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr(feature = "serde", serde(rename_all = "snake_case"))] #[derive(Debug, PartialEq, Clone, Copy)] pub enum PadProperty { Bga, @@ -362,6 +372,8 @@ simple_to_from_string! { pad_prop_castellated <-> Castellated, } +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr(feature = "serde", serde(rename_all = "snake_case"))] #[derive(Debug, PartialEq, Clone)] pub struct Chamfer { pub top_left: bool, @@ -406,6 +418,8 @@ impl ToSexpr for Chamfer { } } +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr(feature = "serde", serde(rename_all = "snake_case"))] #[derive(Debug, PartialEq, Clone)] pub struct Net { pub code: i32, @@ -439,6 +453,8 @@ impl ToSexpr for Net { } } +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr(feature = "serde", serde(rename_all = "snake_case"))] #[derive(Debug, PartialEq, Clone)] pub struct CustomPadOptions { pub clearance: CustomPadClearanceKind, @@ -476,6 +492,8 @@ impl ToSexpr for CustomPadOptions { } } +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr(feature = "serde", serde(rename_all = "snake_case"))] #[derive(Debug, PartialEq, Clone, Copy)] pub enum CustomPadClearanceKind { Outline, @@ -488,6 +506,8 @@ simple_to_from_string! { convexhull <-> ConvexHull, } +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr(feature = "serde", serde(rename_all = "snake_case"))] #[derive(Debug, PartialEq, Clone, Copy)] pub enum CustomPadAnchorShape { Rect, diff --git a/kicad_format/src/common/pad/primitive.rs b/kicad_format/src/common/pad/primitive.rs index 8020fe7..05efa12 100644 --- a/kicad_format/src/common/pad/primitive.rs +++ b/kicad_format/src/common/pad/primitive.rs @@ -8,12 +8,17 @@ use crate::{ simple_to_from_string, KiCadParseError, }; +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr(feature = "serde", serde(rename_all = "snake_case"))] #[derive(Debug, PartialEq, Clone)] pub struct PadGraphicsPrimitive { pub kind: PadGraphicsPrimitiveKind, pub width: f32, } +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr(feature = "serde", serde(rename_all = "snake_case"))] +#[cfg_attr(feature = "serde", serde(tag = "type"))] #[derive(Debug, PartialEq, Clone)] pub enum PadGraphicsPrimitiveKind { Line(PadLine), @@ -229,12 +234,16 @@ impl ToSexpr for PadGraphicsPrimitive { } } +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr(feature = "serde", serde(rename_all = "snake_case"))] #[derive(Debug, PartialEq, Clone)] pub struct PadLine { pub start: Vec2D, pub end: Vec2D, } +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr(feature = "serde", serde(rename_all = "snake_case"))] #[derive(Debug, PartialEq, Clone)] pub struct PadRectangle { pub start: Vec2D, @@ -242,6 +251,8 @@ pub struct PadRectangle { pub fill: PrimitiveFillMode, } +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr(feature = "serde", serde(rename_all = "snake_case"))] #[derive(Debug, PartialEq, Clone)] pub struct PadAnnotationBoundingBox { pub start: Vec2D, @@ -249,6 +260,8 @@ pub struct PadAnnotationBoundingBox { pub fill: PrimitiveFillMode, } +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr(feature = "serde", serde(rename_all = "snake_case"))] #[derive(Debug, PartialEq, Clone)] pub struct PadCircle { pub center: Vec2D, @@ -256,6 +269,8 @@ pub struct PadCircle { pub fill: PrimitiveFillMode, } +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr(feature = "serde", serde(rename_all = "snake_case"))] #[derive(Debug, PartialEq, Clone)] pub struct PadArc { pub start: Vec2D, @@ -263,17 +278,23 @@ pub struct PadArc { pub end: Vec2D, } +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr(feature = "serde", serde(rename_all = "snake_case"))] #[derive(Debug, PartialEq, Clone)] pub struct PadPolygon { pub points: CoordinatePointList, pub fill: PrimitiveFillMode, } +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr(feature = "serde", serde(rename_all = "snake_case"))] #[derive(Debug, PartialEq, Clone)] pub struct PadBezier { pub points: [Vec2D; 4], } +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr(feature = "serde", serde(rename_all = "snake_case"))] #[derive(Debug, PartialEq, Clone, Copy)] pub enum PrimitiveFillMode { Solid, diff --git a/kicad_format/src/common/shape.rs b/kicad_format/src/common/shape.rs index 526083c..7ffed21 100644 --- a/kicad_format/src/common/shape.rs +++ b/kicad_format/src/common/shape.rs @@ -15,8 +15,8 @@ use crate::{ use super::{Color, CoordinatePointList, Stroke, Uuid, Vec2D}; /// Common properties shared by the different shapes. -/// - +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr(feature = "serde", serde(rename_all = "snake_case"))] #[derive(Debug, PartialEq, Clone)] pub struct Shape { pub private: bool, @@ -26,6 +26,9 @@ pub struct Shape { pub uuid: Option, } +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr(feature = "serde", serde(rename_all = "snake_case"))] +#[cfg_attr(feature = "serde", serde(tag = "type"))] #[derive(Debug, PartialEq, Clone)] pub enum ShapeKind { Arc(Arc), @@ -154,6 +157,8 @@ impl ToSexpr for Shape { } } +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr(feature = "serde", serde(rename_all = "snake_case"))] #[derive(Debug, PartialEq, Clone)] pub struct Arc { pub start: Vec2D, @@ -161,29 +166,40 @@ pub struct Arc { pub end: Vec2D, } +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr(feature = "serde", serde(rename_all = "snake_case"))] #[derive(Debug, PartialEq, Clone)] pub struct Circle { pub center: Vec2D, pub radius: f32, } +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr(feature = "serde", serde(rename_all = "snake_case"))] #[derive(Debug, PartialEq, Clone)] pub struct Rectangle { pub start: Vec2D, pub end: Vec2D, } +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr(feature = "serde", serde(rename_all = "snake_case"))] #[derive(Debug, PartialEq, Clone)] pub struct Bezier { pub points: [Vec2D; 4], } +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr(feature = "serde", serde(rename_all = "snake_case"))] #[derive(Debug, PartialEq, Clone)] pub struct PolyLine { pub points: CoordinatePointList, } /// The mode to use when filling in the shape +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr(feature = "serde", serde(rename_all = "snake_case"))] +#[cfg_attr(feature = "serde", serde(tag = "type"))] #[derive(Debug, PartialEq, Default, Clone)] pub enum ShapeFillMode { /// Graphic item not filled. diff --git a/kicad_format/src/common/symbol.rs b/kicad_format/src/common/symbol.rs index 3c72297..748e3bb 100644 --- a/kicad_format/src/common/symbol.rs +++ b/kicad_format/src/common/symbol.rs @@ -19,6 +19,8 @@ use super::{ Position, Stroke, TextEffects, Vec2D, }; +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr(feature = "serde", serde(rename_all = "snake_case"))] #[derive(Debug, PartialEq, Clone)] pub struct LibSymbol { pub id: LibraryId, @@ -91,6 +93,9 @@ impl ToSexpr for LibSymbol { } } +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr(feature = "serde", serde(rename_all = "snake_case"))] +#[cfg_attr(feature = "serde", serde(tag = "type"))] #[derive(Debug, PartialEq, Clone)] pub struct LibSymbolSubUnit { pub id: UnitId, @@ -142,6 +147,8 @@ impl ToSexpr for LibSymbolSubUnit { // ############################################################################ +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr(feature = "serde", serde(rename_all = "snake_case"))] #[derive(Debug, PartialEq, Eq, Hash, Clone)] pub struct LibraryId { pub library_nickname: Option, @@ -234,6 +241,8 @@ mod lib_id_tests { } } +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr(feature = "serde", serde(rename_all = "snake_case"))] #[derive(Debug, PartialEq, Clone)] pub struct UnitId { pub parent: String, @@ -311,6 +320,8 @@ mod unit_id_tests { // ############################################################################ /// See `pin_names` in [`LibSymbol`]. +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr(feature = "serde", serde(rename_all = "snake_case"))] #[derive(Debug, PartialEq, Clone)] pub struct PinNames { pub offset: Option, @@ -353,6 +364,8 @@ impl ToSexpr for PinNames { /// TODO: rename to "field" as used in the kicad codebase? /// /// https://dev-docs.kicad.org/en/file-formats/sexpr-intro/#_symbol_properties +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr(feature = "serde", serde(rename_all = "snake_case"))] #[derive(Debug, PartialEq, Clone)] pub struct SymbolProperty { /// The "KEY" string defines the name of the property and must be unique. @@ -419,6 +432,9 @@ impl ToSexpr for SymbolProperty { /// definitions. /// /// https://dev-docs.kicad.org/en/file-formats/sexpr-intro/#_symbol_graphic_items +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr(feature = "serde", serde(rename_all = "snake_case"))] +#[cfg_attr(feature = "serde", serde(tag = "type"))] #[derive(Debug, PartialEq, Clone)] pub enum LibSymbolGraphicsItem { Shape(Shape), @@ -475,6 +491,8 @@ impl ToSexpr for LibSymbolGraphicsItem { } } +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr(feature = "serde", serde(rename_all = "snake_case"))] #[derive(Debug, PartialEq, Clone)] pub struct LibSymbolText { pub private: bool, @@ -518,6 +536,8 @@ impl ToSexpr for LibSymbolText { } /// UNDOCUMENTED +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr(feature = "serde", serde(rename_all = "snake_case"))] #[derive(Debug, PartialEq, Clone)] pub struct LibSymbolTextBox { pub private: bool, @@ -577,6 +597,8 @@ impl ToSexpr for LibSymbolTextBox { /// The pin token defines a pin in a symbol definition. /// /// https://dev-docs.kicad.org/en/file-formats/sexpr-intro/#_symbol_pin +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr(feature = "serde", serde(rename_all = "snake_case"))] #[derive(Debug, PartialEq, Clone)] pub struct Pin { /// The `PIN_ELECTRICAL_TYPE` defines the pin electrical connection. See @@ -687,6 +709,8 @@ impl ToSexpr for Pin { } /// See `electrical_kind` in [`Pin`]. +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr(feature = "serde", serde(rename_all = "snake_case"))] #[derive(Debug, PartialEq, Clone, Copy, Default)] pub enum PinElectricalKind { /// Pin is an input. @@ -733,6 +757,8 @@ simple_to_from_string! { } /// See `graphical_style` in [`Pin`]. +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr(feature = "serde", serde(rename_all = "snake_case"))] #[derive(Debug, PartialEq, Clone, Copy, Default)] pub enum PinGraphicalStyle { #[default] @@ -760,6 +786,8 @@ simple_to_from_string! { non_logic <-> NonLogic, } +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr(feature = "serde", serde(rename_all = "snake_case"))] #[derive(Debug, PartialEq, Clone)] pub struct PinAlternate { pub name: String, diff --git a/kicad_format/src/common/zone.rs b/kicad_format/src/common/zone.rs index 1e9ae90..90fd0d5 100644 --- a/kicad_format/src/common/zone.rs +++ b/kicad_format/src/common/zone.rs @@ -11,6 +11,8 @@ use crate::{ use super::{CoordinatePointList, LayerId, Uuid}; +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr(feature = "serde", serde(rename_all = "snake_case"))] #[derive(Debug, PartialEq, Clone)] pub struct Zone { pub locked: bool, @@ -200,6 +202,8 @@ impl ToSexpr for Zone { } } +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr(feature = "serde", serde(rename_all = "snake_case"))] #[derive(Debug, PartialEq, Clone)] pub struct Hatch { pub style: HatchStyle, @@ -231,6 +235,8 @@ impl ToSexpr for Hatch { } } +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr(feature = "serde", serde(rename_all = "snake_case"))] #[derive(Debug, PartialEq, Clone, Copy)] pub enum HatchStyle { None, @@ -245,6 +251,8 @@ simple_to_from_string! { full <-> Full, } +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr(feature = "serde", serde(rename_all = "snake_case"))] #[derive(Debug, PartialEq, Clone, Copy)] pub enum TearDropKind { PadVia, @@ -257,6 +265,8 @@ simple_to_from_string! { track_end <-> TrackEnd, } +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr(feature = "serde", serde(rename_all = "snake_case"))] #[derive(Debug, PartialEq, Clone)] pub struct PadConnection { pub kind: Option, @@ -291,6 +301,8 @@ impl ToSexpr for PadConnection { } } +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr(feature = "serde", serde(rename_all = "snake_case"))] #[derive(Debug, PartialEq, Clone, Copy)] pub enum PadConnectionKind { ThruHoleOnly, @@ -305,6 +317,8 @@ simple_to_from_string! { no <-> No, } +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr(feature = "serde", serde(rename_all = "snake_case"))] #[derive(Debug, PartialEq, Clone)] pub struct KeepOutSettings { pub tracks: KeepOut, @@ -353,6 +367,8 @@ impl ToSexpr for KeepOutSettings { } } +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr(feature = "serde", serde(rename_all = "snake_case"))] #[derive(Debug, PartialEq, Clone, Copy)] pub enum KeepOut { Allowed, @@ -365,6 +381,8 @@ simple_to_from_string! { not_allowed <-> NotAllowed, } +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr(feature = "serde", serde(rename_all = "snake_case"))] #[derive(Debug, PartialEq, Clone)] pub struct FillSettings { pub filled: bool, @@ -481,6 +499,8 @@ impl ToSexpr for FillSettings { } } +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr(feature = "serde", serde(rename_all = "snake_case"))] #[derive(Debug, PartialEq, Clone, Copy)] pub enum ZoneFillMode { Solid, @@ -493,6 +513,8 @@ simple_to_from_string! { hatch <-> Hatched, } +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr(feature = "serde", serde(rename_all = "snake_case"))] #[derive(Debug, PartialEq, Clone, Copy)] pub enum FillSmoothingStyle { Chamfer, @@ -505,8 +527,10 @@ simple_to_from_string! { fillet <-> Fillet, } -#[repr(u8)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr(feature = "serde", serde(rename_all = "snake_case"))] #[derive(Debug, PartialEq, Clone, Copy)] +#[repr(u8)] pub enum FillIslandRemovalMode { AlwaysRemoveIslands = 0, NeverRemoveIslands = 1, @@ -526,8 +550,10 @@ impl TryFrom for FillIslandRemovalMode { } } -#[repr(u8)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr(feature = "serde", serde(rename_all = "snake_case"))] #[derive(Debug, PartialEq, Clone, Copy)] +#[repr(u8)] pub enum HatchSmoothingLevel { NoSmoothing = 0, Fillet = 1, @@ -553,6 +579,8 @@ impl TryFrom for HatchSmoothingLevel { } } +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr(feature = "serde", serde(rename_all = "snake_case"))] #[derive(Debug, PartialEq, Clone, Copy)] pub enum HatchBorderAlgorithm { UseHatchThickness, @@ -565,6 +593,8 @@ simple_to_from_string! { min_thickness <-> UseZoneMinimumThickness, } +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr(feature = "serde", serde(rename_all = "snake_case"))] #[derive(Debug, PartialEq, Clone)] pub struct FilledPolygon { pub layer: LayerId, @@ -607,6 +637,8 @@ impl ToSexpr for FilledPolygon { } } +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr(feature = "serde", serde(rename_all = "snake_case"))] #[derive(Debug, PartialEq, Clone)] pub struct FilledSegments { pub layer: LayerId, diff --git a/kicad_format/src/footprint_library.rs b/kicad_format/src/footprint_library.rs index 1f0f80c..680144b 100644 --- a/kicad_format/src/footprint_library.rs +++ b/kicad_format/src/footprint_library.rs @@ -20,6 +20,8 @@ use crate::{ /// that footprints a footprint library file include a file header, and omit /// several attributes such as the footprint position, rotation, and locked /// status. +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr(feature = "serde", serde(rename_all = "snake_case"))] #[derive(Debug, PartialEq, Clone)] pub struct FootprintLibraryFile { pub name: String, diff --git a/kicad_format/src/pcb/graphics/dimension.rs b/kicad_format/src/pcb/graphics/dimension.rs index 009eca1..7331131 100644 --- a/kicad_format/src/pcb/graphics/dimension.rs +++ b/kicad_format/src/pcb/graphics/dimension.rs @@ -11,6 +11,8 @@ use super::text::PcbText; /// The `dimension` token defines a dimension object. /// /// https://dev-docs.kicad.org/en/file-formats/sexpr-intro/#_dimension +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr(feature = "serde", serde(rename_all = "snake_case"))] #[derive(Debug, PartialEq, Clone)] pub struct PcbDimension { /// The optional `locked` token specifies if the dimension can be moved. @@ -58,6 +60,8 @@ impl ToSexpr for PcbDimension { } /// See `kind` field in [`Dimension`]. +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr(feature = "serde", serde(rename_all = "snake_case"))] #[derive(Debug, PartialEq, Clone, Copy)] pub enum DimensionKind { Aligned, @@ -67,6 +71,8 @@ pub enum DimensionKind { Radial, } +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr(feature = "serde", serde(rename_all = "snake_case"))] #[derive(Debug, PartialEq, Clone)] pub struct DimensionFormat { /// The optional `prefix` token attribute defines the string to add to the @@ -105,8 +111,10 @@ pub struct DimensionFormat { } /// See `units` field in [`DimensionUnits`]. -#[repr(u8)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr(feature = "serde", serde(rename_all = "snake_case"))] #[derive(Debug, PartialEq, Clone, Copy)] +#[repr(u8)] pub enum DimensionUnits { Inches = 0, /// Thousandths of an inch @@ -116,8 +124,10 @@ pub enum DimensionUnits { } /// See `units_format` field in [`DimensionFormat`]. -#[repr(u8)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr(feature = "serde", serde(rename_all = "snake_case"))] #[derive(Debug, PartialEq, Clone, Copy)] +#[repr(u8)] pub enum DimensionUnitsFormat { NoSuffix = 0, BareSuffix = 1, @@ -125,6 +135,8 @@ pub enum DimensionUnitsFormat { } /// https://dev-docs.kicad.org/en/file-formats/sexpr-intro/#_dimension_style +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr(feature = "serde", serde(rename_all = "snake_case"))] #[derive(Debug, PartialEq, Clone)] pub struct DimensionStyle { /// The `thickness` token attribute defines the line thickness of the @@ -161,8 +173,10 @@ pub struct DimensionStyle { } /// See `text_position_mode` field in [`DimensionStyle`]. -#[repr(u8)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr(feature = "serde", serde(rename_all = "snake_case"))] #[derive(Debug, PartialEq, Clone, Copy)] +#[repr(u8)] pub enum DimensionTextPositionMode { Outside = 0, Inline = 1, @@ -170,8 +184,10 @@ pub enum DimensionTextPositionMode { } /// See `text_frame` field in [`DimensionStyle`]. -#[repr(u8)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr(feature = "serde", serde(rename_all = "snake_case"))] #[derive(Debug, PartialEq, Clone, Copy)] +#[repr(u8)] pub enum TextFrameKind { NoFrame = 0, Rectangle = 1, diff --git a/kicad_format/src/pcb/graphics/mod.rs b/kicad_format/src/pcb/graphics/mod.rs index 82a9238..44ccdfc 100644 --- a/kicad_format/src/pcb/graphics/mod.rs +++ b/kicad_format/src/pcb/graphics/mod.rs @@ -19,6 +19,9 @@ pub mod text; // TODO: Dimension +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr(feature = "serde", serde(rename_all = "snake_case"))] +#[cfg_attr(feature = "serde", serde(tag = "type"))] #[derive(Debug, PartialEq, Clone)] pub enum PcbGraphicsItem { Text(PcbText), diff --git a/kicad_format/src/pcb/graphics/shape.rs b/kicad_format/src/pcb/graphics/shape.rs index 0d5f940..0ea477d 100644 --- a/kicad_format/src/pcb/graphics/shape.rs +++ b/kicad_format/src/pcb/graphics/shape.rs @@ -6,6 +6,8 @@ use crate::{ KiCadParseError, }; +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr(feature = "serde", serde(rename_all = "snake_case"))] #[derive(Debug, PartialEq, Clone)] pub struct PcbShape { pub locked: bool, @@ -98,6 +100,9 @@ impl PcbShape { } } +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr(feature = "serde", serde(rename_all = "snake_case"))] +#[cfg_attr(feature = "serde", serde(tag = "type"))] #[derive(Debug, PartialEq, Clone)] pub enum PcbShapeKind { Line(PcbLine), @@ -291,12 +296,16 @@ impl ToSexpr for PcbShape { } } +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr(feature = "serde", serde(rename_all = "snake_case"))] #[derive(Debug, PartialEq, Clone)] pub struct PcbLine { pub start: Vec2D, pub end: Vec2D, } +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr(feature = "serde", serde(rename_all = "snake_case"))] #[derive(Debug, PartialEq, Clone)] pub struct PcbRectangle { pub start: Vec2D, @@ -304,6 +313,8 @@ pub struct PcbRectangle { pub fill: SimpleFillMode, } +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr(feature = "serde", serde(rename_all = "snake_case"))] #[derive(Debug, PartialEq, Clone)] pub struct PcbCircle { pub center: Vec2D, @@ -311,6 +322,8 @@ pub struct PcbCircle { pub fill: SimpleFillMode, } +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr(feature = "serde", serde(rename_all = "snake_case"))] #[derive(Debug, PartialEq, Clone)] pub struct PcbArc { pub start: Vec2D, @@ -318,12 +331,16 @@ pub struct PcbArc { pub end: Vec2D, } +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr(feature = "serde", serde(rename_all = "snake_case"))] #[derive(Debug, PartialEq, Clone)] pub struct PcbPolygon { pub points: CoordinatePointList, pub fill: SimpleFillMode, } +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr(feature = "serde", serde(rename_all = "snake_case"))] #[derive(Debug, PartialEq, Clone)] pub struct PcbBezier { pub points: [Vec2D; 4], diff --git a/kicad_format/src/pcb/graphics/text.rs b/kicad_format/src/pcb/graphics/text.rs index cddafd8..d044667 100644 --- a/kicad_format/src/pcb/graphics/text.rs +++ b/kicad_format/src/pcb/graphics/text.rs @@ -6,6 +6,8 @@ use crate::{ KiCadParseError, }; +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr(feature = "serde", serde(rename_all = "snake_case"))] #[derive(Debug, PartialEq, Clone)] pub struct PcbText { pub locked: bool, @@ -78,6 +80,8 @@ impl ToSexpr for PcbText { } } +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr(feature = "serde", serde(rename_all = "snake_case"))] #[derive(Debug, PartialEq, Clone)] pub struct PcbTextBox { pub locked: bool, @@ -189,6 +193,8 @@ impl ToSexpr for PcbTextBox { } } +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr(feature = "serde", serde(rename_all = "snake_case"))] #[derive(Debug, PartialEq, Clone)] pub enum TextBoxPosition { StartEnd(Vec2D, Vec2D), diff --git a/kicad_format/src/pcb/mod.rs b/kicad_format/src/pcb/mod.rs index 78e3486..52b3200 100644 --- a/kicad_format/src/pcb/mod.rs +++ b/kicad_format/src/pcb/mod.rs @@ -26,6 +26,8 @@ pub mod graphics; pub mod setup; /// A PCB board file (`.kicad_pcb` file). +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr(feature = "serde", serde(rename_all = "snake_case"))] #[derive(Debug, PartialEq, Clone)] pub struct PcbFile { pub version: u32, @@ -355,6 +357,8 @@ impl ToSexpr for PcbFile { // ############################################################################ /// General board settings. Currently only holds the board thickness. +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr(feature = "serde", serde(rename_all = "snake_case"))] #[derive(Debug, PartialEq, Clone)] pub struct GeneralSettings { pub thickness: f32, @@ -389,6 +393,8 @@ impl ToSexpr for GeneralSettings { /// ```text /// (0 "F.Cu" signal ["Front Copper"]) /// ``` +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr(feature = "serde", serde(rename_all = "snake_case"))] #[derive(Debug, PartialEq, Clone)] pub struct BoardLayer { pub layer: LayerId, @@ -441,6 +447,8 @@ impl ToSexpr for BoardLayer { /// /// Only copper layers can be `Signal`, `Power`, `Mixed`, or `Jumper`. All /// other layers should be the `User` type. +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr(feature = "serde", serde(rename_all = "snake_case"))] #[derive(Debug, PartialEq, Default, Copy, Clone)] pub enum BoardLayerKind { #[default] @@ -463,6 +471,9 @@ simple_to_from_string! { // ############################################################################ /// Different types of tracks on the PCB. +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr(feature = "serde", serde(rename_all = "snake_case"))] +#[cfg_attr(feature = "serde", serde(tag = "type"))] #[derive(Debug, PartialEq, Clone)] pub enum Track { Segment(TrackSegment), @@ -508,6 +519,8 @@ impl ToSexpr for Track { } /// The simplest form of a track, a straight line segment. +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr(feature = "serde", serde(rename_all = "snake_case"))] #[derive(Debug, PartialEq, Clone)] pub struct TrackSegment { pub locked: bool, @@ -565,6 +578,8 @@ impl ToSexpr for TrackSegment { } /// A via, a hole in the PCB that connects two layers. +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr(feature = "serde", serde(rename_all = "snake_case"))] #[derive(Debug, PartialEq, Clone)] pub struct TrackVia { pub kind: ViaKind, @@ -686,6 +701,8 @@ impl ToSexpr for TrackVia { } /// The type of via, which determines which layers it can connect. +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr(feature = "serde", serde(rename_all = "snake_case"))] #[derive(Debug, PartialEq, Default, Clone, Copy)] pub enum ViaKind { /// Always a through hole via @@ -706,6 +723,8 @@ simple_to_from_string! { } /// An arc, a curved track on the PCB. +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr(feature = "serde", serde(rename_all = "snake_case"))] #[derive(Debug, PartialEq, Clone)] pub struct TrackArc { pub locked: bool, diff --git a/kicad_format/src/pcb/setup.rs b/kicad_format/src/pcb/setup.rs index 69b53eb..2ff2ac8 100644 --- a/kicad_format/src/pcb/setup.rs +++ b/kicad_format/src/pcb/setup.rs @@ -12,6 +12,8 @@ use crate::{ /// Properties of the PCB such as physical layer stackup, clearances, origins, /// and plot options +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr(feature = "serde", serde(rename_all = "snake_case"))] #[derive(Debug, PartialEq, Clone)] pub struct BoardSetup { pub stackup: Option, @@ -99,6 +101,8 @@ impl ToSexpr for BoardSetup { // ############################################################################ /// The physical layer stackup of the PCB +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr(feature = "serde", serde(rename_all = "snake_case"))] #[derive(Debug, PartialEq, Clone)] pub struct BoardStackup { pub layers: Vec, @@ -193,6 +197,8 @@ impl ToSexpr for BoardStackup { /// FIXME: Intentionally not supporting the `locked` token within the /// `thickness` token attribute because it's not common and I dont feel like /// parsing that :) +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr(feature = "serde", serde(rename_all = "snake_case"))] #[derive(Debug, PartialEq, Clone)] pub struct StackupLayer { pub id: StackupLayerId, @@ -258,6 +264,9 @@ impl ToSexpr for StackupLayer { /// Layers in the board stackup are either defined board layers or dielectric /// layers (i.e. FR4) +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr(feature = "serde", serde(rename_all = "snake_case"))] +#[cfg_attr(feature = "serde", serde(tag = "type"))] #[derive(Debug, PartialEq, Clone)] pub enum StackupLayerId { BoardLayer(LayerId), @@ -297,6 +306,8 @@ impl ToSexpr for StackupLayerId { } } +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr(feature = "serde", serde(rename_all = "snake_case"))] #[derive(Debug, PartialEq, Clone)] pub enum EdgeConnectorConstraints { /// No edge connector in board @@ -317,6 +328,8 @@ simple_to_from_string! { // ############################################################################ /// Large field of settings that control how the PCB is plotted +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr(feature = "serde", serde(rename_all = "snake_case"))] #[derive(Debug, PartialEq, Clone)] pub struct PcbPlotOptions { /// Set of layers to plot @@ -662,8 +675,10 @@ fn assemble_bit_field(bit_field: u64) -> String { format!("0x{:0>7x}_{:0>8x}", high, low) } -#[repr(u8)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr(feature = "serde", serde(rename_all = "snake_case"))] #[derive(Debug, PartialEq, Clone, Copy)] +#[repr(u8)] pub enum OutlineMode { Sketch = 0, Filled = 1, @@ -685,8 +700,10 @@ impl TryFrom for OutlineMode { } } -#[repr(u8)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr(feature = "serde", serde(rename_all = "snake_case"))] #[derive(Debug, PartialEq, Clone, Copy)] +#[repr(u8)] pub enum PlotFormat { Hpgl = 0, Gerber = 1, @@ -716,8 +733,10 @@ impl TryFrom for PlotFormat { } } -#[repr(u8)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr(feature = "serde", serde(rename_all = "snake_case"))] #[derive(Debug, PartialEq, Clone, Copy)] +#[repr(u8)] pub enum DrillMarks { No = 0, Small = 1, diff --git a/kicad_format/src/schematic/mod.rs b/kicad_format/src/schematic/mod.rs index edb51d7..d5b7b17 100644 --- a/kicad_format/src/schematic/mod.rs +++ b/kicad_format/src/schematic/mod.rs @@ -21,6 +21,8 @@ use self::{sheet::Sheet, symbol::Symbol}; pub mod sheet; pub mod symbol; +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr(feature = "serde", serde(rename_all = "snake_case"))] #[derive(Debug, PartialEq, Clone, Copy)] pub enum SheetPinShape { Unspecified, @@ -47,6 +49,8 @@ simple_to_from_string! { rectangle <-> Rectangle, } +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr(feature = "serde", serde(rename_all = "snake_case"))] #[derive(Debug, PartialEq, Clone)] pub struct SchematicFile { pub version: u32, @@ -181,6 +185,8 @@ impl ToSexpr for SchematicFile { } } +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr(feature = "serde", serde(rename_all = "snake_case"))] #[derive(Debug, PartialEq, Clone)] pub struct BusAlias { pub name: String, @@ -227,6 +233,8 @@ impl ToSexpr for BusAlias { } } +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr(feature = "serde", serde(rename_all = "snake_case"))] #[derive(Debug, PartialEq, Clone)] pub struct Junction { pub position: Position, @@ -271,6 +279,8 @@ impl ToSexpr for Junction { } } +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr(feature = "serde", serde(rename_all = "snake_case"))] #[derive(Debug, PartialEq, Clone)] pub struct NoConnect { pub position: Position, @@ -301,6 +311,8 @@ impl ToSexpr for NoConnect { } } +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr(feature = "serde", serde(rename_all = "snake_case"))] #[derive(Debug, PartialEq, Clone)] pub struct BusEntry { pub position: Position, @@ -346,6 +358,8 @@ impl ToSexpr for BusEntry { } /// Wires, Buses, or PolyLines +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr(feature = "serde", serde(rename_all = "snake_case"))] #[derive(Debug, PartialEq, Clone)] pub struct SchematicLine { pub kind: SchematicLineKind, @@ -394,6 +408,8 @@ impl ToSexpr for SchematicLine { } } +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr(feature = "serde", serde(rename_all = "snake_case"))] #[derive(Debug, PartialEq, Clone)] pub enum SchematicLineKind { Wire, @@ -408,6 +424,8 @@ simple_to_from_string! { polyline <-> PolyLine, } +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr(feature = "serde", serde(rename_all = "snake_case"))] #[derive(Debug, PartialEq, Clone)] pub struct SchematicTextBox { pub text: String, @@ -464,6 +482,8 @@ impl ToSexpr for SchematicTextBox { } } +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr(feature = "serde", serde(rename_all = "snake_case"))] #[derive(Debug, PartialEq, Clone)] pub struct SchematicText { pub text: String, @@ -508,6 +528,8 @@ impl ToSexpr for SchematicText { } } +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr(feature = "serde", serde(rename_all = "snake_case"))] #[derive(Debug, PartialEq, Clone)] pub struct LocalLabel { pub text: String, @@ -564,6 +586,8 @@ impl ToSexpr for LocalLabel { } } +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr(feature = "serde", serde(rename_all = "snake_case"))] #[derive(Debug, PartialEq, Clone)] pub struct GlobalLabel { pub text: String, @@ -627,6 +651,8 @@ impl ToSexpr for GlobalLabel { } // TODO: This is a duplicate of the GlobalLabel struct. It should be refactored to use the same struct. +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr(feature = "serde", serde(rename_all = "snake_case"))] #[derive(Debug, PartialEq, Clone)] pub struct HierarchicalLabel { pub text: String, @@ -689,6 +715,8 @@ impl ToSexpr for HierarchicalLabel { } } +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr(feature = "serde", serde(rename_all = "snake_case"))] #[derive(Debug, PartialEq, Clone)] pub struct SchematicSheetInstance { pub path: String, diff --git a/kicad_format/src/schematic/sheet.rs b/kicad_format/src/schematic/sheet.rs index 18014df..5c6bae3 100644 --- a/kicad_format/src/schematic/sheet.rs +++ b/kicad_format/src/schematic/sheet.rs @@ -10,6 +10,8 @@ use crate::{ use super::SheetPinShape; +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr(feature = "serde", serde(rename_all = "snake_case"))] #[derive(Debug, PartialEq, Clone)] pub struct Sheet { pub position: Position, @@ -94,6 +96,8 @@ impl ToSexpr for Sheet { } } +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr(feature = "serde", serde(rename_all = "snake_case"))] #[derive(Debug, PartialEq, Clone)] pub struct SheetHierarchicalPin { @@ -143,6 +147,8 @@ impl ToSexpr for SheetHierarchicalPin { } } +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr(feature = "serde", serde(rename_all = "snake_case"))] #[derive(Debug, PartialEq, Clone)] pub struct SheetInstance { pub project: String, diff --git a/kicad_format/src/schematic/symbol.rs b/kicad_format/src/schematic/symbol.rs index 7ec21a5..b8135ee 100644 --- a/kicad_format/src/schematic/symbol.rs +++ b/kicad_format/src/schematic/symbol.rs @@ -20,6 +20,8 @@ use crate::{ /// Not to be confused with [`LibSymbol`](crate::common::symbol::LibSymbol), /// [`DerivedLibSymbol`](crate::symbol_library::DerivedLibSymbol), or /// [`LibSymbolSubUnit`](crate::common::symbol::LibSymbolSubUnit). +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr(feature = "serde", serde(rename_all = "snake_case"))] #[derive(Debug, PartialEq, Clone)] pub struct Symbol { pub lib_name: Option, @@ -134,6 +136,8 @@ impl ToSexpr for Symbol { } } +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr(feature = "serde", serde(rename_all = "snake_case"))] #[derive(Debug, PartialEq, Clone)] pub struct Mirror { pub x: bool, @@ -167,8 +171,10 @@ impl ToSexpr for Mirror { } } -#[repr(u8)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr(feature = "serde", serde(rename_all = "snake_case"))] #[derive(Debug, PartialEq, Clone, Copy)] +#[repr(u8)] pub enum SymbolConversion { Base = 1, Demorgan = 2, @@ -188,6 +194,8 @@ impl TryFrom for SymbolConversion { } } +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr(feature = "serde", serde(rename_all = "snake_case"))] #[derive(Debug, PartialEq, Clone)] pub struct Pin { pub number: String, @@ -230,6 +238,8 @@ impl ToSexpr for Pin { } } +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr(feature = "serde", serde(rename_all = "snake_case"))] #[derive(Debug, PartialEq, Clone)] pub struct SymbolInstanceProject { pub project: String, @@ -265,6 +275,8 @@ impl ToSexpr for SymbolInstanceProject { } } +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr(feature = "serde", serde(rename_all = "snake_case"))] #[derive(Debug, PartialEq, Clone)] pub struct SymbolInstance { pub path: String, diff --git a/kicad_format/src/symbol_library.rs b/kicad_format/src/symbol_library.rs index b9f3783..9ff3d9e 100644 --- a/kicad_format/src/symbol_library.rs +++ b/kicad_format/src/symbol_library.rs @@ -10,6 +10,8 @@ use crate::{ /// Stores a collection of symbols which may or may not be derived from other /// symbols within the library +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr(feature = "serde", serde(rename_all = "snake_case"))] #[derive(Debug, PartialEq, Clone)] pub struct SymbolLibraryFile { /// The `version` token attribute defines the symbol library version using @@ -56,6 +58,9 @@ impl ToSexpr for SymbolLibraryFile { } /// A symbol definition can be a root symbol or a derived symbol +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr(feature = "serde", serde(rename_all = "snake_case"))] +#[cfg_attr(feature = "serde", serde(tag = "type"))] #[derive(Debug, PartialEq, Clone)] pub enum SymbolDefinition { RootSymbol(LibSymbol), @@ -98,6 +103,8 @@ impl ToSexpr for SymbolDefinition { /// A symbol which has been derived from another (root) symbol within the /// library +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr(feature = "serde", serde(rename_all = "snake_case"))] #[derive(Debug, PartialEq, Clone)] pub struct DerivedLibSymbol { pub id: LibraryId, diff --git a/kicad_sexpr/Cargo.toml b/kicad_sexpr/Cargo.toml index 3f01c03..df5d5ef 100644 --- a/kicad_sexpr/Cargo.toml +++ b/kicad_sexpr/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "kicad_sexpr" -version = "0.1.0" +version = "0.1.1" edition = "2021" description = "A library for parsing the KiCad S-Expression encoding format" authors = ["Adrian Wowk "] @@ -8,4 +8,8 @@ license = "MIT" [dependencies] nom = "7.1.3" +serde = { version = "1.0.130", features = ["derive"], optional = true } thiserror = "1.0.56" + +[features] +serde = ["dep:serde"] diff --git a/kicad_sexpr/src/sexpr.rs b/kicad_sexpr/src/sexpr.rs index d4f7082..dfcbaa3 100644 --- a/kicad_sexpr/src/sexpr.rs +++ b/kicad_sexpr/src/sexpr.rs @@ -18,6 +18,9 @@ use super::string::parse_string; pub type SexprList = Vec; +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr(feature = "serde", serde(rename_all = "snake_case"))] +#[cfg_attr(feature = "serde", serde(tag = "type"))] #[derive(Debug, PartialEq, Clone)] pub enum Sexpr { List(SexprList),