diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml deleted file mode 100644 index 84408f8..0000000 --- a/.gitlab-ci.yml +++ /dev/null @@ -1,41 +0,0 @@ -# This file is a template, and might need editing before it works on your project. -# This is a sample GitLab CI/CD configuration file that should run without any modifications. -# It demonstrates a basic 3 stage CI/CD pipeline. Instead of real tests or scripts, -# it uses echo commands to simulate the pipeline execution. -# -# A pipeline is composed of independent jobs that run scripts, grouped into stages. -# Stages run in sequential order, but jobs within stages run in parallel. -# -# For more information, see: https://docs.gitlab.com/ee/ci/yaml/index.html#stages -# -# You can copy and paste this template into a new `.gitlab-ci.yml` file. -# You should not add this template to an existing `.gitlab-ci.yml` file by using the `include:` keyword. -# -# To contribute improvements to CI/CD templates, please follow the Development guide at: -# https://docs.gitlab.com/ee/development/cicd/templates.html -# This specific template is located at: -# https://gitlab.com/gitlab-org/gitlab/-/blob/master/lib/gitlab/ci/templates/Getting-Started.gitlab-ci.yml - -stages: # List of stages for jobs, and their order of execution - - build - - test - -.setup-rust: - image: rust:latest - before_script: - - rustup component add clippy rustfmt - -rust-latest: - stage: build - extends: .setup-rust - script: - - cargo build --verbose - - cargo test --verbose - - cargo doc - -lint-test-job: # This job also runs in the test stage. - stage: test # It can run at the same time as unit-test-job (in parallel). - extends: .setup-rust - script: - - cargo fmt -- --check - - cargo clippy diff --git a/CHANGELOG.md b/CHANGELOG.md deleted file mode 100644 index 7a44951..0000000 --- a/CHANGELOG.md +++ /dev/null @@ -1,14 +0,0 @@ -# Changelog - -All notable changes to this project will be documented in this file. - -The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), -and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). - -## [0.1.0] - -### Added - -- Implemented basic code generation covering current CSR XML. - -[0.1.0]: https://gitlab.cern.ch/wotsubo/endcap-sl-software-ri-generator/~/tags/v0.1.0 diff --git a/Cargo.lock b/Cargo.lock index 29222d1..dfaf1ae 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -11,21 +11,6 @@ dependencies = [ "memchr", ] -[[package]] -name = "android-tzdata" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0" - -[[package]] -name = "android_system_properties" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" -dependencies = [ - "libc", -] - [[package]] name = "anstream" version = "0.6.18" @@ -82,296 +67,21 @@ version = "1.0.95" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "34ac096ce696dc2fcabef30516bb13c0a68a11d30131d3df6f04711467681b04" -[[package]] -name = "autocfg" -version = "1.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" - -[[package]] -name = "block-buffer" -version = "0.10.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" -dependencies = [ - "generic-array", -] - -[[package]] -name = "bumpalo" -version = "3.17.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1628fb46dfa0b37568d12e5edd512553eccf6a22a78e8bde00bb4aed84d5bdbf" - -[[package]] -name = "camino" -version = "1.1.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b96ec4966b5813e2c0507c1f86115c8c5abaadc3980879c3424042a02fd1ad3" -dependencies = [ - "serde", -] - -[[package]] -name = "cargo-platform" -version = "0.1.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e35af189006b9c0f00a064685c727031e3ed2d8020f7ba284d78cc2671bd36ea" -dependencies = [ - "serde", -] - -[[package]] -name = "cargo_metadata" -version = "0.19.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8769706aad5d996120af43197bf46ef6ad0fda35216b4505f926a365a232d924" -dependencies = [ - "camino", - "cargo-platform", - "semver", - "serde", - "serde_json", - "thiserror", -] - -[[package]] -name = "cc" -version = "1.2.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "755717a7de9ec452bf7f3f1a3099085deabd7f2962b861dae91ecd7a365903d2" -dependencies = [ - "shlex", -] - -[[package]] -name = "cfg-if" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" - -[[package]] -name = "chrono" -version = "0.4.39" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e36cc9d416881d2e24f9a963be5fb1cd90966419ac844274161d10488b3e825" -dependencies = [ - "android-tzdata", - "iana-time-zone", - "js-sys", - "num-traits", - "wasm-bindgen", - "windows-targets", -] - -[[package]] -name = "clap" -version = "4.5.28" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3e77c3243bd94243c03672cb5154667347c457ca271254724f9f393aee1c05ff" -dependencies = [ - "clap_builder", - "clap_derive", -] - -[[package]] -name = "clap_builder" -version = "4.5.27" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b26884eb4b57140e4d2d93652abfa49498b938b3c9179f9fc487b0acc3edad7" -dependencies = [ - "anstream", - "anstyle", - "clap_lex", - "strsim", -] - -[[package]] -name = "clap_derive" -version = "4.5.28" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf4ced95c6f4a675af3da73304b9ac4ed991640c36374e4b46795c49e17cf1ed" -dependencies = [ - "heck", - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "clap_lex" -version = "0.7.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f46ad14479a25103f283c0f10005961cf086d8dc42205bb44c46ac563475dca6" - [[package]] name = "colorchoice" version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5b63caa9aa9397e2d9480a9b13673856c78d8ac123288526c37d7839f2a86990" -[[package]] -name = "core-foundation-sys" -version = "0.8.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" - -[[package]] -name = "cpufeatures" -version = "0.2.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280" -dependencies = [ - "libc", -] - -[[package]] -name = "crossbeam-deque" -version = "0.8.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9dd111b7b7f7d55b72c0a6ae361660ee5853c9af73f70c3c2ef6858b950e2e51" -dependencies = [ - "crossbeam-epoch", - "crossbeam-utils", -] - -[[package]] -name = "crossbeam-epoch" -version = "0.9.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e" -dependencies = [ - "crossbeam-utils", -] - -[[package]] -name = "crossbeam-utils" -version = "0.8.21" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" - -[[package]] -name = "crypto-common" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" -dependencies = [ - "generic-array", - "typenum", -] - -[[package]] -name = "darling" -version = "0.20.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f63b86c8a8826a49b8c21f08a2d07338eec8d900540f8630dc76284be802989" -dependencies = [ - "darling_core", - "darling_macro", -] - -[[package]] -name = "darling_core" -version = "0.20.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95133861a8032aaea082871032f5815eb9e98cef03fa916ab4500513994df9e5" -dependencies = [ - "fnv", - "ident_case", - "proc-macro2", - "quote", - "strsim", - "syn", -] - -[[package]] -name = "darling_macro" -version = "0.20.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d336a2a514f6ccccaa3e09b02d41d35330c07ddf03a62165fcec10bb561c7806" -dependencies = [ - "darling_core", - "quote", - "syn", -] - -[[package]] -name = "deranged" -version = "0.3.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b42b6fa04a440b495c8b04d0e71b707c585f83cb9cb28cf8cd0d976c315e31b4" -dependencies = [ - "powerfmt", -] - -[[package]] -name = "derive_builder" -version = "0.20.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "507dfb09ea8b7fa618fcf76e953f4f5e192547945816d5358edffe39f6f94947" -dependencies = [ - "derive_builder_macro", -] - -[[package]] -name = "derive_builder_core" -version = "0.20.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d5bcf7b024d6835cfb3d473887cd966994907effbe9227e8c8219824d06c4e8" -dependencies = [ - "darling", - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "derive_builder_macro" -version = "0.20.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab63b0e2bf4d5928aff72e83a7dace85d7bba5fe12dcc3c5a572d78caffd3f3c" -dependencies = [ - "derive_builder_core", - "syn", -] - -[[package]] -name = "digest" -version = "0.10.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" -dependencies = [ - "block-buffer", - "crypto-common", -] - -[[package]] -name = "either" -version = "1.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0" - [[package]] name = "endcap-sl-software-ri-generator" version = "0.1.0" dependencies = [ "anyhow", - "chrono", - "clap", "env_logger", - "heck", - "hex", - "itertools", "log", - "prettyplease", - "proc-macro2", - "quote", "roxmltree", - "sha2", - "syn", "thiserror", - "typenum", - "vergen-gitcl", ] [[package]] @@ -397,106 +107,18 @@ dependencies = [ "log", ] -[[package]] -name = "fnv" -version = "1.0.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" - -[[package]] -name = "generic-array" -version = "0.14.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" -dependencies = [ - "typenum", - "version_check", -] - -[[package]] -name = "heck" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" - -[[package]] -name = "hex" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" - [[package]] name = "humantime" version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" -[[package]] -name = "iana-time-zone" -version = "0.1.61" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "235e081f3925a06703c2d0117ea8b91f042756fd6e7a6e5d901e8ca1a996b220" -dependencies = [ - "android_system_properties", - "core-foundation-sys", - "iana-time-zone-haiku", - "js-sys", - "wasm-bindgen", - "windows-core 0.52.0", -] - -[[package]] -name = "iana-time-zone-haiku" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" -dependencies = [ - "cc", -] - -[[package]] -name = "ident_case" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" - [[package]] name = "is_terminal_polyfill" version = "1.70.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf" -[[package]] -name = "itertools" -version = "0.14.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b192c782037fadd9cfa75548310488aabdbf3d2da73885b31bd0abd03351285" -dependencies = [ - "either", -] - -[[package]] -name = "itoa" -version = "1.0.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d75a2a4b1b190afb6f5425f10f6a8f959d2ea0b9c2b1d79553551850539e4674" - -[[package]] -name = "js-sys" -version = "0.3.77" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1cfaf33c695fc6e08064efbc1f72ec937429614f25eef83af942d0e227c3a28f" -dependencies = [ - "once_cell", - "wasm-bindgen", -] - -[[package]] -name = "libc" -version = "0.2.169" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5aba8db14291edd000dfcc4d620c7ebfb122c613afb886ca8803fa4e128a20a" - [[package]] name = "log" version = "0.4.25" @@ -509,61 +131,12 @@ version = "2.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" -[[package]] -name = "ntapi" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e8a3895c6391c39d7fe7ebc444a87eb2991b2a0bc718fdabd071eec617fc68e4" -dependencies = [ - "winapi", -] - -[[package]] -name = "num-conv" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" - -[[package]] -name = "num-traits" -version = "0.2.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" -dependencies = [ - "autocfg", -] - -[[package]] -name = "num_threads" -version = "0.1.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c7398b9c8b70908f6371f47ed36737907c87c52af34c268fed0bf0ceb92ead9" -dependencies = [ - "libc", -] - [[package]] name = "once_cell" version = "1.20.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775" -[[package]] -name = "powerfmt" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" - -[[package]] -name = "prettyplease" -version = "0.2.29" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6924ced06e1f7dfe3fa48d57b9f74f55d8915f5036121bef647ef4b204895fac" -dependencies = [ - "proc-macro2", - "syn", -] - [[package]] name = "proc-macro2" version = "1.0.93" @@ -582,26 +155,6 @@ dependencies = [ "proc-macro2", ] -[[package]] -name = "rayon" -version = "1.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b418a60154510ca1a002a752ca9714984e21e4241e804d32555251faf8b78ffa" -dependencies = [ - "either", - "rayon-core", -] - -[[package]] -name = "rayon-core" -version = "1.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1465873a3dfdaa8ae7cb14b4383657caab0b3e8a0aa9ae8e04b044854c8dfce2" -dependencies = [ - "crossbeam-deque", - "crossbeam-utils", -] - [[package]] name = "regex" version = "1.11.1" @@ -637,91 +190,6 @@ version = "0.20.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6c20b6793b5c2fa6553b250154b78d6d0db37e72700ae35fad9387a46f487c97" -[[package]] -name = "rustc_version" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92" -dependencies = [ - "semver", -] - -[[package]] -name = "rustversion" -version = "1.0.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7c45b9784283f1b2e7fb61b42047c2fd678ef0960d4f6f1eba131594cc369d4" - -[[package]] -name = "ryu" -version = "1.0.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ea1a2d0a644769cc99faa24c3ad26b379b786fe7c36fd3c546254801650e6dd" - -[[package]] -name = "semver" -version = "1.0.25" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f79dfe2d285b0488816f30e700a7438c5a73d816b5b7d3ac72fbc48b0d185e03" -dependencies = [ - "serde", -] - -[[package]] -name = "serde" -version = "1.0.217" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02fc4265df13d6fa1d00ecff087228cc0a2b5f3c0e87e258d8b94a156e984c70" -dependencies = [ - "serde_derive", -] - -[[package]] -name = "serde_derive" -version = "1.0.217" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a9bf7cf98d04a2b28aead066b7496853d4779c9cc183c440dbac457641e19a0" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "serde_json" -version = "1.0.138" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d434192e7da787e94a6ea7e9670b26a036d0ca41e0b7efb2676dd32bae872949" -dependencies = [ - "itoa", - "memchr", - "ryu", - "serde", -] - -[[package]] -name = "sha2" -version = "0.10.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" -dependencies = [ - "cfg-if", - "cpufeatures", - "digest", -] - -[[package]] -name = "shlex" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" - -[[package]] -name = "strsim" -version = "0.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" - [[package]] name = "syn" version = "2.0.96" @@ -733,20 +201,6 @@ dependencies = [ "unicode-ident", ] -[[package]] -name = "sysinfo" -version = "0.33.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fc858248ea01b66f19d8e8a6d55f41deaf91e9d495246fd01368d99935c6c01" -dependencies = [ - "core-foundation-sys", - "libc", - "memchr", - "ntapi", - "rayon", - "windows", -] - [[package]] name = "thiserror" version = "2.0.11" @@ -767,45 +221,6 @@ dependencies = [ "syn", ] -[[package]] -name = "time" -version = "0.3.37" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "35e7868883861bd0e56d9ac6efcaaca0d6d5d82a2a7ec8209ff492c07cf37b21" -dependencies = [ - "deranged", - "itoa", - "libc", - "num-conv", - "num_threads", - "powerfmt", - "serde", - "time-core", - "time-macros", -] - -[[package]] -name = "time-core" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3" - -[[package]] -name = "time-macros" -version = "0.2.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2834e6017e3e5e4b9834939793b282bc03b37a3336245fa820e35e233e2a85de" -dependencies = [ - "num-conv", - "time-core", -] - -[[package]] -name = "typenum" -version = "1.17.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" - [[package]] name = "unicode-ident" version = "1.0.16" @@ -818,196 +233,6 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" -[[package]] -name = "vergen" -version = "9.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0d2f179f8075b805a43a2a21728a46f0cc2921b3c58695b28fa8817e103cd9a" -dependencies = [ - "anyhow", - "cargo_metadata", - "derive_builder", - "regex", - "rustc_version", - "rustversion", - "sysinfo", - "time", - "vergen-lib", -] - -[[package]] -name = "vergen-gitcl" -version = "1.0.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2f89d70a58a4506a6079cedf575c64cf51649ccbb4e02a63dac539b264b7711" -dependencies = [ - "anyhow", - "derive_builder", - "rustversion", - "time", - "vergen", - "vergen-lib", -] - -[[package]] -name = "vergen-lib" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b07e6010c0f3e59fcb164e0163834597da68d1f864e2b8ca49f74de01e9c166" -dependencies = [ - "anyhow", - "derive_builder", - "rustversion", -] - -[[package]] -name = "version_check" -version = "0.9.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" - -[[package]] -name = "wasm-bindgen" -version = "0.2.100" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1edc8929d7499fc4e8f0be2262a241556cfc54a0bea223790e71446f2aab1ef5" -dependencies = [ - "cfg-if", - "once_cell", - "rustversion", - "wasm-bindgen-macro", -] - -[[package]] -name = "wasm-bindgen-backend" -version = "0.2.100" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f0a0651a5c2bc21487bde11ee802ccaf4c51935d0d3d42a6101f98161700bc6" -dependencies = [ - "bumpalo", - "log", - "proc-macro2", - "quote", - "syn", - "wasm-bindgen-shared", -] - -[[package]] -name = "wasm-bindgen-macro" -version = "0.2.100" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fe63fc6d09ed3792bd0897b314f53de8e16568c2b3f7982f468c0bf9bd0b407" -dependencies = [ - "quote", - "wasm-bindgen-macro-support", -] - -[[package]] -name = "wasm-bindgen-macro-support" -version = "0.2.100" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ae87ea40c9f689fc23f209965b6fb8a99ad69aeeb0231408be24920604395de" -dependencies = [ - "proc-macro2", - "quote", - "syn", - "wasm-bindgen-backend", - "wasm-bindgen-shared", -] - -[[package]] -name = "wasm-bindgen-shared" -version = "0.2.100" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a05d73b933a847d6cccdda8f838a22ff101ad9bf93e33684f39c1f5f0eece3d" -dependencies = [ - "unicode-ident", -] - -[[package]] -name = "winapi" -version = "0.3.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" -dependencies = [ - "winapi-i686-pc-windows-gnu", - "winapi-x86_64-pc-windows-gnu", -] - -[[package]] -name = "winapi-i686-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" - -[[package]] -name = "winapi-x86_64-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" - -[[package]] -name = "windows" -version = "0.57.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "12342cb4d8e3b046f3d80effd474a7a02447231330ef77d71daa6fbc40681143" -dependencies = [ - "windows-core 0.57.0", - "windows-targets", -] - -[[package]] -name = "windows-core" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9" -dependencies = [ - "windows-targets", -] - -[[package]] -name = "windows-core" -version = "0.57.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2ed2439a290666cd67ecce2b0ffaad89c2a56b976b736e6ece670297897832d" -dependencies = [ - "windows-implement", - "windows-interface", - "windows-result", - "windows-targets", -] - -[[package]] -name = "windows-implement" -version = "0.57.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9107ddc059d5b6fbfbffdfa7a7fe3e22a226def0b2608f72e9d552763d3e1ad7" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "windows-interface" -version = "0.57.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29bee4b38ea3cde66011baa44dba677c432a78593e202392d1e9070cf2a7fca7" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "windows-result" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e383302e8ec8515204254685643de10811af0ed97ea37210dc26fb0032647f8" -dependencies = [ - "windows-targets", -] - [[package]] name = "windows-sys" version = "0.59.0" diff --git a/Cargo.toml b/Cargo.toml index 9e3b9a8..8a02725 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,11 +1,7 @@ [package] name = "endcap-sl-software-ri-generator" version = "0.1.0" -authors = ["Wataru Otsubo "] edition = "2021" -description = "A generator of register interface for mpsoc software from register map in xml format" -repository = "https://gitlab.cern.ch/wotsubo/endcap-sl-software-ri-generator" -build = "build.rs" [[bin]] name = "endcap-sl-software-ri-generator" @@ -17,21 +13,7 @@ path = "src/lib.rs" [dependencies] anyhow = "1.0.95" -chrono = "0.4.39" -clap = { version = "4.5.28", features = ["derive"] } env_logger = "0.11.6" -heck = "0.5" -hex = "0.4.3" -itertools = "0.14" log = "0.4" -prettyplease = "0.2" -proc-macro2 = "1.0.93" -quote = "1.0" roxmltree = "0.20" -sha2 = "0.10" -syn = "2.0.96" thiserror = "2.0" -typenum = "1.17.0" - -[build-dependencies] -vergen-gitcl = { version = "1.0.0", features = ["build", "cargo", "rustc", "si"] } diff --git a/README-ja.md b/README-ja.md deleted file mode 100644 index 2e03644..0000000 --- a/README-ja.md +++ /dev/null @@ -1,79 +0,0 @@ -# Endcap SL Software RI Generator - -これはXMLのレジスタマップからMPSoCソフトで使う用のコードを生成するソフトです。 - -XMLおよびそのスキーマは[L0 Muon Endcap/Endcap Sl CSR XML](https://gitlab.cern.ch/l0muon-endcap/endcap-sl-csr-xml)にあります。 -生成されたコードは[MPSoC Software](https://gitlab.cern.ch/wotsubo/mpsoc-software)で使うことが想定されています。 -そこに`RegisterSpec`などのレジスタ向けのトレイトが定義されてます。 - -## 使い方 - -このプロジェクトでは、バイナリとライブラリの両方のクレートを提供しています。 -バイナリクレートはシェルから使うことができ、ライブラリクレートは他のプログラムから使うためのものです。 - -### ビルド環境の構築 - -このコードは[Rust](https://www.rust-lang.org/ja/)で書かれているので、[rustup](https://www.rust-lang.org/ja/tools/install)をインストールする必要があります。 -rustupのインストールには公式サイトにある`curl`スクリプトを使うか、あるいはシステムのパッケージマネージャを使うことができます。 -`cargo`を実行してみることでインストールのチェックができます。 - -`cargo`はlxplusにインストールされているみたいなので、それも使えるかもしれません(ただし、バージョンは最新ではありません)。 - -### バイナリクレートの使い方 - -```bash -cargo build --bins --release -``` -を実行します。 -`--release`はオプションです。 - -`target/release`に入ってるバイナリファイルを実行するか、`cargo run -- `で実行できます。 - -詳しくは`--help`を見てください。 - -### ライブラリクレートの使い方 - -```bash -cargo doc --open -``` - -で閲覧できるドキュメントを見てください。 - -## 開発 - -```bash -cargo doc --document-private-items --open -``` - -でみれるプライベートアイテムを含んだドキュメントを見てください。 - -テストなどは以下のコマンドで実行できます -```bash -$ cargo test # テスト -$ cargo fmt # フォーマット -$ cargo clippy # リント (`rustup component add clippy`でインストールできます) -``` - -### rust-analyzer - -開発には[rust-analyzer](https://rust-analyzer.github.io)を使用することを __強く推奨__ します。 -推論された型の表示や補完に関して必要不可欠な上、フォーマットやclippyを実行することができます。 - -### CIについて - -ビルドとフォーマットとclippyのテストが走ります。 -フォーマットやclippyのチェックをしてpushしてください。 - -### Rustについて - -以下のウェブサイトでRustを良く学べます。 - -- [The Book](https://doc.rust-jp.rs/book-ja/) - -もしくはターミナルで -```bash -rustup doc -``` -を実行してみてください。 -様々な有益なドキュメントへのリンクが載っています(自分はThe Bookとstandard libraryのドキュメントとRust By Exampleが役に立ちました)。 - diff --git a/README.md b/README.md deleted file mode 100644 index f903963..0000000 --- a/README.md +++ /dev/null @@ -1,82 +0,0 @@ -# Endcap SL Software RI Generator - -[日本語版](README-ja.md) - -Generates register interface for mpsoc software from register map in xml format. - -The XML and its schema definition are in [L0 Muon Endcap/Endcap Sl CSR XML](https://gitlab.cern.ch/l0muon-endcap/endcap-sl-csr-xml). -The generated code is intended to be used in [MPSoC Software](https://gitlab.cern.ch/wotsubo/mpsoc-software), which provides definition of register traits (`RegisterSpec`) used in the generated code. - -## Usage - -This project provides both binary and library crates. -Binary crates can be used from shell, while library crates can be used in other programs. - -### Setting up building environment - -This code is written in [Rust](https://www.rust-lang.org), so you need to install [rustup](https://www.rust-lang.org/tools/install). -You can use either officially provided `curl` script, or system package manager to install. -You can check the installation by executing `cargo` in the terminal. - -Note that `cargo` is available on lxplus, so you might be able to use that (it is not the latest version though). - -### Binary crate usage - -Execute - -```bash -cargo build --bins --release -``` - -to build. -`--release` is optional(this is a compiler optimization config). - -Execute the binary generated in `target/release/`, or run with `cargo run -- `. - -See the `--help` for more information. - -### Library crate usage - -See the doc, which is available with - -```bash -cargo doc --open -``` - -## Development - -See the doc with private items with - -```bash -cargo doc --document-private-items --open -``` - -You can execute test, format and lint with: - -```bash -$ cargo test # test -$ cargo fmt # format -$ cargo clippy # lint (run `rustup component add clippy` to install) -``` - -### rust-analyzer - -It is __heavily recommended__ to use [rust-analyzer](https://rust-analyzer.github.io) in development. -It is not only essential for displaying inferred types and completion, but also it can execute formatter and clippy. - -### About CI - -In the CI, test for build, format and clippy run. -Please format your code and check clippy before pushing. - -### About Rust - -You can learn Rust with the following webpage. - -- [The Book](https://doc.rust-lang.org/book/) - -Or in terminal, execute -```bash -rustup doc -``` -It has a lot of links to helpful documents (personally, I appreciate "The Book", std library doc and "Rust By Example"). diff --git a/build.rs b/build.rs deleted file mode 100644 index 2e8f364..0000000 --- a/build.rs +++ /dev/null @@ -1,18 +0,0 @@ -use vergen_gitcl::{BuildBuilder, Emitter, GitclBuilder}; - -fn main() -> Result<(), Box> { - // Get build metadata - let build = BuildBuilder::default().build_timestamp(true).build()?; - let gitcl = GitclBuilder::default() - .commit_date(true) - .describe(false, true, None) - .commit_timestamp(true) - .sha(false) - .build()?; - Emitter::default() - .add_instructions(&build)? - .add_instructions(&gitcl)? - .emit()?; - - Ok(()) -} diff --git a/src/converter.rs b/src/converter.rs index 3ccc699..c9fcabe 100644 --- a/src/converter.rs +++ b/src/converter.rs @@ -1,13 +1,8 @@ -//! Convert DOM to register interface defined in [`crate::types`], complementing optional parameters. -//! -//! root: [`Module::from_xml_dom`] -//! -//! error: [`DomConversionError`] +//! Convert DOM to register interface, complementing optional parameters. use std::{num, str}; use roxmltree::{Node, TextPos}; -use sha2::{Digest, Sha256}; use thiserror::Error; use crate::parser::{ParseCustomBool, ParseEnumError, ParsePrefixedU32, ParsePrefixedU32Error}; @@ -16,7 +11,6 @@ use crate::types::{ Value, }; -/// Possible errors in conversion, with positional information. #[derive(Debug, Error, PartialEq)] pub enum DomConversionError { #[error("attribute {attr} not found in element: {start} - {end}", start = pos.0, end = pos.1)] @@ -55,11 +49,8 @@ pub enum DomConversionError { param: &'static str, pos: (TextPos, TextPos), }, - #[error("other dom conversion error: {comment}: {start} - {end}", start = pos.0, end = pos.1)] - OtherError { - comment: &'static str, - pos: (TextPos, TextPos), - }, + #[error("other dom conversion error: {0}")] + OtherError(String), } impl DomConversionError { @@ -119,15 +110,6 @@ impl DomConversionError { found, } } - - fn other_error(comment: &'static str, node: Node) -> Self { - let range = node.range(); - let doc = node.document(); - Self::OtherError { - comment, - pos: (doc.text_pos_at(range.start), doc.text_pos_at(range.end)), - } - } } mod util { @@ -139,11 +121,7 @@ mod util { pub(crate) fn get_name(node: Node) -> Result { match node.attribute("name") { - Some(name) if !name.is_empty() => Ok(name.to_string()), - Some(_name) => Err(DomConversionError::other_error( - "name cannot be empty", - node, - )), + Some(name) => Ok(name.to_string()), None => Err(DomConversionError::attr_not_found("name", node)), } } @@ -211,7 +189,6 @@ impl Module { desc: node.attribute("desc").map(str::to_string), elements_bitstring: child_bitstrings, elements_other: child_other, - xmlhash: Sha256::digest(node.document().input_text()).into(), }) } } @@ -304,9 +281,8 @@ impl Block { .next() { Some(s) => Ok(s.to_string()), - None => Err(DomConversionError::other_error( - "decoder format is not yet fixed", - node, + None => Err(DomConversionError::OtherError( + "decoder format is not yet fixed".to_string(), )), }?, }; @@ -347,18 +323,6 @@ impl Register { .map_err(|e| DomConversionError::parse_prefixed_u32_error(e, "addr", node))?, None => 0, }; - let r#type = util::get_type(node) - .transpose()? - .map_or_else( - || { - node.ancestors() - .filter_map(util::get_type) - .next() - .transpose() - }, - |x| Ok(Some(x)), - )? - .ok_or_else(|| DomConversionError::parameter_completion_error("type", node))?; let mask = node .attribute("mask") .map(|addr| { @@ -388,41 +352,15 @@ impl Register { .transpose()?; let desc = node.attribute("desc").map(str::to_string); - let children: Vec<_> = node + let children = node .children() .filter(|node| node.is_element() && node.tag_name().name().eq("field")) .map(Field::from_xml_dom) .collect::>()?; - // Validation - if mask.is_some() && !children.is_empty() { - return Err(DomConversionError::other_error( - "both mask and field are used in the same register", - node, - )); - } - if default.is_some() && !children.is_empty() { - return Err(DomConversionError::other_error( - "both default and field are used in the same register", - node, - )); - } - if let (Some(mask), Some(default)) = (mask, default) { - if default & !(mask) != 0 { - log::warn!( - "default value {} doesn't fit mask {}: {} - {}", - default, - mask, - node.document().text_pos_at(node.range().start), - node.document().text_pos_at(node.range().end) - ) - } - } - Ok(Register { name, addr, - r#type, mask, modf, multiple, @@ -434,13 +372,13 @@ impl Register { } impl Memory { - pub(crate) fn from_xml_dom(_node: Node) -> Result { + pub(crate) fn from_xml_dom(node: Node) -> Result { todo!() } } impl Fifo { - pub(crate) fn from_xml_dom(_node: Node) -> Result { + pub(crate) fn from_xml_dom(node: Node) -> Result { todo!() } } @@ -486,7 +424,6 @@ impl Field { .map(Value::from_xml_dom) .collect::>()?; - // Validation if let Some(default) = default { if default & !(mask) != 0 { log::warn!( diff --git a/src/generator.rs b/src/generator.rs deleted file mode 100644 index 7e9c2bc..0000000 --- a/src/generator.rs +++ /dev/null @@ -1,468 +0,0 @@ -//! Generate register interface rust code from types in [`crate::types`]. -//! -//! root: [`Module::generate_code`] -//! -//! # For developers -//! Pass `--document-private-items` to see non-public items. - -use std::{ - collections::HashMap, - path::{self, PathBuf}, -}; - -use crate::{ - meta::{ - GENERATOR_BUILD_TIMESTAMP, GENERATOR_GIT_COMMIT_TIMESTAMP, GENERATOR_GIT_DESCRIBE, - GENERATOR_GIT_SHA, - }, - type_traits::GetName, - types::{Block, Module, ModuleBlockElements, Register}, -}; -use chrono::Local; -use heck::{ToSnakeCase, ToUpperCamelCase}; -use itertools::Itertools; -use quote::quote; -use thiserror::Error; - -#[derive(Debug, Error)] -pub enum CodeGenError { - #[error("tokenization(syn) error: {0}")] - SynError(#[from] syn::Error), - #[error("failed to create file: {0}")] - FilePathError(String), - #[error("parent is required for {module}")] - ParentMissing { module: &'static str }, - #[error("Unsupported structure: {}", name)] - UnsupportedStructure { name: &'static str }, -} - -mod util { - use crate::types::DataType; - - use super::CodeGenError; - - pub(super) fn parse_to_ident(s: &str) -> Result { - Ok(syn::parse_str(s)?) - } - - pub(super) fn parse_to_literal(s: &str) -> Result { - Ok(syn::parse_str(s)?) - } - - // currently only U32 is used, so `dead_code` for Debug, PartialEq - #[allow(dead_code)] - #[derive(Debug, PartialEq)] - pub(crate) enum RustUxTypes { - Bool, - U8, - U16, - U32, - } - - impl RustUxTypes { - /// Derive appropriate rust types for `mask`ed value. - pub(super) fn from_mask(mask: u32) -> RustUxTypes { - match 32 - mask.leading_zeros() - mask.trailing_zeros() { - 0 => panic!("mask cannot be 0"), - 1 => RustUxTypes::Bool, - x if 1 < x && x <= 8 => RustUxTypes::U8, - x if 8 < x && x <= 16 => RustUxTypes::U16, - x if 16 < x && x <= 32 => RustUxTypes::U32, - _ => panic!("supposed not to be reachable"), - } - } - - pub(super) fn to_rust_type_token(&self) -> proc_macro2::Ident { - match self { - RustUxTypes::Bool => parse_to_ident("bool").unwrap(), - RustUxTypes::U8 => parse_to_ident("u8").unwrap(), - RustUxTypes::U16 => parse_to_ident("u16").unwrap(), - RustUxTypes::U32 => parse_to_ident("u32").unwrap(), - } - } - } - - impl From<&DataType> for RustUxTypes { - fn from(value: &DataType) -> Self { - match value { - DataType::D32 => Self::U32, - } - } - } - - #[cfg(test)] - mod test { - use super::RustUxTypes; - - #[test] - fn rustuxtypes_from_mask() { - assert_eq!(RustUxTypes::from_mask(0x1), RustUxTypes::Bool); - assert_eq!(RustUxTypes::from_mask(0x20), RustUxTypes::Bool); - assert_eq!(RustUxTypes::from_mask(0x4000), RustUxTypes::Bool); - assert_eq!(RustUxTypes::from_mask(0x80_0000), RustUxTypes::Bool); - assert_eq!(RustUxTypes::from_mask(0x100_0000), RustUxTypes::Bool); - - assert_eq!(RustUxTypes::from_mask(0x0300_0000), RustUxTypes::U8); - assert_eq!(RustUxTypes::from_mask(0x0000_01e0), RustUxTypes::U8); - - assert_eq!(RustUxTypes::from_mask(0x0000_01f0), RustUxTypes::U8); - assert_eq!(RustUxTypes::from_mask(0x000f_f000), RustUxTypes::U8); - - assert_eq!(RustUxTypes::from_mask(0x0fff_0000), RustUxTypes::U16); - assert_eq!(RustUxTypes::from_mask(0x0f0f_0000), RustUxTypes::U16); - assert_eq!(RustUxTypes::from_mask(0x010f_8000), RustUxTypes::U16); - - assert_eq!(RustUxTypes::from_mask(0xffff_f000), RustUxTypes::U32); - assert_eq!(RustUxTypes::from_mask(0x1fff_ff00), RustUxTypes::U32); - } - - #[test] - fn rustuxtypes_to_token() { - assert_eq!( - RustUxTypes::U8.to_rust_type_token(), - proc_macro2::Ident::new("u8", proc_macro2::Span::call_site()) - ) - } - } -} - -impl Module { - pub fn generate_code(self) -> Result, CodeGenError> { - let build_metadata = format!( - " -# Build metadata - -- timestamp: {} - -## CSR XML - -- sha256: {} -- git describe: TODO (after building step is fixed) -- git commit timestamp: TODO -- git SHA: TODO - -## Generator - -- build timestamp: {} -- git describe: {} -- git commit timestamp: {} -- git SHA: {} -", - Local::now().to_rfc3339_opts(chrono::SecondsFormat::Nanos, false), - hex::encode(self.xmlhash), - GENERATOR_BUILD_TIMESTAMP, - GENERATOR_GIT_DESCRIBE, - GENERATOR_GIT_COMMIT_TIMESTAMP, - GENERATOR_GIT_SHA, - ); - let files = self.generate_register_interface(None, None, HashMap::new())?; - Ok(files - .into_iter() - .map( - |(path, tokens)| -> Result<(PathBuf, syn::File), syn::Error> { - let tokens = if path - .file_name() - .is_some_and(|file| file == "register_interface.rs") - { - quote! { - #![doc = #build_metadata] - - #tokens - } - } else { - tokens - }; - let file: syn::File = syn::parse2(tokens)?; - Ok((path, file)) - }, - ) - .process_results(|kv| HashMap::from_iter(kv))?) - } -} - -trait CodeGen { - /// `parent_name` in UpperCamelCase. - fn generate_register_interface( - self, - parent_name: Option, - parent_path: Option, - files: HashMap, - ) -> Result, CodeGenError>; -} - -impl CodeGen for Module { - fn generate_register_interface( - self, - _: Option, - _: Option, - mut files: HashMap, - ) -> std::result::Result, CodeGenError> { - if !self.elements_bitstring.is_empty() { - todo!("bitstring generation is not yet implemented") - } - - let child_mods = self - .elements_other - .iter() - .map(|e| { - util::parse_to_ident(&e.get_name().to_snake_case()).map(|child_name| { - quote! { - pub mod #child_name; - } - }) - }) - .collect::, _>>()?; - let out = quote! { - #(#child_mods)* - }; - files.insert(PathBuf::from("./register_interface.rs"), out); - - let ident_register_interface = util::parse_to_ident("RegisterInterface").unwrap(); - let register_interface_mod = PathBuf::from("register_interface"); - let files = self - .elements_other - .into_iter() - .try_fold(files, |files, e| { - e.generate_register_interface( - Some(ident_register_interface.clone()), - Some(register_interface_mod.clone()), - files, - ) - })?; - - Ok(files) - } -} - -impl CodeGen for ModuleBlockElements { - fn generate_register_interface( - self, - parent_name: Option, - parent_path: Option, - files: HashMap, - ) -> Result, CodeGenError> { - match self { - ModuleBlockElements::Block(block) => { - block.generate_register_interface(parent_name, parent_path, files) - } - ModuleBlockElements::Register(register) => { - register.generate_register_interface(parent_name, parent_path, files) - } - ModuleBlockElements::Memory(_memory) => todo!(), - ModuleBlockElements::Fifo(_fifo) => todo!(), - } - } -} - -impl CodeGen for Block { - fn generate_register_interface( - self, - parent_name: Option, - parent_path: Option, - mut files: HashMap, - ) -> Result, CodeGenError> { - if self.multiple.is_some() { - // Plan: expand automatically, or same as register? - return Err(CodeGenError::UnsupportedStructure { - name: "multiple in block", - }); - } - let parent_name = parent_name.ok_or(CodeGenError::ParentMissing { module: "Block" })?; - let parent_path = parent_path.ok_or(CodeGenError::ParentMissing { module: "Block" })?; - - let snake_case_name = util::parse_to_ident(&self.name.to_snake_case())?; - let upper_camel_name = util::parse_to_ident(&self.name.to_upper_camel_case())?; - let addr = util::parse_to_literal(&format!("0x{:x}", self.addr))?; - let desc = self.desc.unwrap_or("".to_string()); - - let accessors_methods = self.elements.iter().map(|e| { - let child_name = e.get_name(); - let snake_case_name = util::parse_to_ident(&child_name.to_snake_case())?; - match e { - ModuleBlockElements::Block(_) => { - let child_upper_camel_name = util::parse_to_ident(&child_name.to_upper_camel_case())?; - Ok(quote! { - pub fn #snake_case_name(&self) -> #snake_case_name::#child_upper_camel_name { - #snake_case_name::#child_upper_camel_name::new(self.mem_ptr) - } - }) - }, - ModuleBlockElements::Register(register) => { - let child_upper_camel_name = util::parse_to_ident(&format!("Reg{}", child_name.to_upper_camel_case()))?; - match ®ister.multiple { - None => { - Ok(quote! { - pub fn #snake_case_name(&self) -> #snake_case_name::#child_upper_camel_name { - #snake_case_name::#child_upper_camel_name::new(self.mem_ptr) - } - }) - }, - Some(multiple_param) => { - let num_multiple = multiple_param.multiple as usize; - let elements = (0..num_multiple).map(|i| { - let offset = (multiple_param.offset as usize) * i; - quote! { - #snake_case_name::#child_upper_camel_name::new(unsafe { self.mem_ptr.add(#offset) } ) - } - }); - Ok(quote! { - pub fn #snake_case_name(&self) -> [#snake_case_name::#child_upper_camel_name; #num_multiple] { - [ #(#elements),* ] - } - }) - }, - } - }, - ModuleBlockElements::Memory(_memory) => todo!(), - ModuleBlockElements::Fifo(_fifo) => todo!(), - } - }).collect::, CodeGenError>>()?; - - let parent_struct = if parent_name == util::parse_to_ident("RegisterInterface").unwrap() { - quote! {#parent_name} - } else { - quote! {#parent_name<'a>} - }; - - let child_mods = self - .elements - .iter() - .map(|e| { - util::parse_to_ident(&e.get_name().to_snake_case()).map(|child_name| { - quote! { - pub mod #child_name; - } - }) - }) - .collect::, _>>()?; - - let out = quote! { - #![doc = #desc] - - use std::marker::PhantomData; - - use super::#parent_name; - - #(#child_mods)* - - const OFFSET: usize = #addr; - - pub struct #upper_camel_name<'a> { - mem_ptr: *mut u32, - _marker: PhantomData<&'a mut #parent_struct>, - } - - impl #upper_camel_name<'_> { - pub(crate) fn new(parent_ptr: *mut u32) -> Self { - #upper_camel_name { - mem_ptr: unsafe { parent_ptr.add(OFFSET) }, - _marker: PhantomData, - } - } - - #(#accessors_methods)* - } - }; - let (out_path, next_parent_path) = mod_file_path(parent_path, &snake_case_name); - log::info!("{:?}", out_path); - if let Some(old_out) = files.insert(out_path.clone(), out.clone()) { - log::error!("path {}", out_path.display()); - log::error!("old {}", old_out.to_string()); - log::error!("new {}", out.to_string()); - return Err(CodeGenError::FilePathError(snake_case_name.to_string())); - }; - - let files = self.elements.into_iter().try_fold(files, |files, e| { - e.generate_register_interface( - Some(upper_camel_name.clone()), - Some(next_parent_path.clone()), - files, - ) - })?; - - Ok(files) - } -} - -/// Get filepath to write the `mod_snake_case_name` and next parent_path. -fn mod_file_path( - parent_path: path::PathBuf, - mod_snake_case_name: &proc_macro2::Ident, -) -> (path::PathBuf, path::PathBuf) { - ( - parent_path.join(format!("{}.rs", mod_snake_case_name)), - parent_path.join(mod_snake_case_name.to_string()), - ) -} - -mod codegen_register; -mod codegen_registerspec_impl; - -/// Internally calls functions in [`codegen_register`] -impl CodeGen for Register { - fn generate_register_interface( - self, - parent_name: Option, - parent_path: Option, - mut files: HashMap, - ) -> Result, CodeGenError> { - let parent_name = parent_name.ok_or(CodeGenError::ParentMissing { module: "Block" })?; - let parent_path = parent_path.ok_or(CodeGenError::ParentMissing { module: "Block" })?; - - let snake_case_name = util::parse_to_ident(&self.name.to_snake_case())?; - let upper_camel_name = util::parse_to_ident(&self.name.to_upper_camel_case())?; - let reg_name = util::parse_to_ident(&format!("Reg{upper_camel_name}"))?; - let addr = util::parse_to_literal(&format!("0x{:x}", self.addr))?; - - let (code_t_def, type_t, type_ux): ( - proc_macro2::TokenStream, - proc_macro2::Ident, - proc_macro2::Ident, - ) = codegen_register::reg_type_def(&self, &upper_camel_name)?; - - let code_reg_def: proc_macro2::TokenStream = - codegen_registerspec_impl::gen_registerspec_impl( - reg_name.clone(), - self.modf, - type_t, - type_ux, - ); - - let desc = self.desc.unwrap_or("".to_string()); - - let out = quote! { - #![doc = #desc] - - use std::marker::PhantomData; - - use crate::register_spec::{DataConversionError, Modifiable, Readable, RegisterSpec, Writable}; - - const OFFSET: usize = #addr; - - pub struct #reg_name<'a> { - mem_ptr: *mut u32, - _marker: PhantomData<&'a mut super::#parent_name<'a>>, - } - - impl #reg_name<'_> { - pub(crate) fn new(parent_ptr: *mut u32) -> Self { - #reg_name { - mem_ptr: unsafe { parent_ptr.add(OFFSET) }, - _marker: PhantomData, - } - } - } - - #code_reg_def - - #code_t_def - }; - - let (out_path, _next_parent_path) = mod_file_path(parent_path, &snake_case_name); - log::info!("{:?}", out_path); - if files.insert(out_path, out).is_some() { - return Err(CodeGenError::FilePathError(snake_case_name.to_string())); - } - Ok(files) - } -} diff --git a/src/generator/codegen_register.rs b/src/generator/codegen_register.rs deleted file mode 100644 index 4445086..0000000 --- a/src/generator/codegen_register.rs +++ /dev/null @@ -1,661 +0,0 @@ -//! Generator for [`Register`]. -//! The entry point is [`reg_type_def`]. - -use heck::{ToShoutySnakeCase, ToSnakeCase, ToUpperCamelCase}; -use itertools::Itertools; -use proc_macro2::{Ident, Literal, TokenStream}; -use quote::quote; - -use crate::types::{DataType, Field, MultipleParams, Register, Value}; - -use super::{ - util::{self, RustUxTypes}, - CodeGenError, -}; - -/// Generate underlying `T` and its implementation for `RegisterSpec`. -/// -/// # Returns -/// tuple of -/// - code of `T` definition and its impls -/// - [`Ident`] of `T` -/// - [`Ident`] of `Ux` -/// -/// # Cases -/// - `T` == `Ux` => [`reg_type_def_simple`] -/// - `T` is masked `Ux` => [`reg_type_def_masked`] -/// - `T` has 1+ fields => [`reg_type_def_with_field`] -pub(super) fn reg_type_def( - reg: &Register, - upper_camel_name: &Ident, -) -> Result<(TokenStream, Ident, Ident), CodeGenError> { - Ok(match reg.elements.is_empty() { - true => match reg.mask { - Some(mask) => reg_type_def_masked(®.r#type, mask, upper_camel_name), - None => reg_type_def_simple(®.r#type), - }, - false => reg_type_def_with_field(®.r#type, ®.elements, upper_camel_name)?, - }) -} - -/// Where `T` == `Ux`. -/// -/// No `T` def nor impl are required. -/// -/// # Returns -/// same as [`reg_type_def`] -fn reg_type_def_simple(basetype: &DataType) -> (TokenStream, Ident, Ident) { - let type_t_ux = { - let x: RustUxTypes = basetype.into(); - x.to_rust_type_token() - }; - - let out = quote! {}; - (out, type_t_ux.clone(), type_t_ux) -} - -/// Where `T` is masked `Ux`. -/// -/// `T` is a one-length "tuple struct" `T(pub Ux)`. -/// `impl TryFrom for T` and `impl From for Ux` are included, -/// but without `impl T`. -/// -/// # Returns -/// same as [`reg_type_def`] -fn reg_type_def_masked( - basetype: &DataType, - mask: u32, - upper_camel_name: &Ident, -) -> (TokenStream, Ident, Ident) { - let type_ux = { - let x: RustUxTypes = basetype.into(); - x.to_rust_type_token() - }; - - let out = quote! { - #[derive(Debug, Clone, Copy, Default)] - pub struct #upper_camel_name(pub #type_ux); - impl TryFrom<#type_ux> for #upper_camel_name { - type Error = DataConversionError<#type_ux, Self>; - - fn try_from(value: #type_ux) -> Result { - Ok(Self(value & #mask)) - } - } - impl From<#upper_camel_name> for #type_ux { - fn from(value: #upper_camel_name) -> Self { - value.0 - } - } - - }; - - (out, upper_camel_name.clone(), type_ux) -} - -/// Where `T` has fields. -/// -/// `T` is a "struct struct" which has a single field `inner: Ux`. -/// Also, a bunch of "mask" constants and getter/setter are defined for each fields. -/// -/// # Returns -/// same as [`reg_type_def`] -/// -/// # Field generation -/// This function calls [`generate_field`] for each [`Field`] entries to generate field definitions. -/// See the doc of `generate_field` for more detail -fn reg_type_def_with_field( - basetype: &DataType, - fields: &[Field], - upper_camel_name: &Ident, -) -> Result<(TokenStream, Ident, Ident), CodeGenError> { - let type_ux = { - let x: RustUxTypes = basetype.into(); - x.to_rust_type_token() - }; - - let (code_masks, code_getters, code_setters): ( - Vec, - Vec, - Vec, - ) = fields - .iter() - .map(|field| generate_field(field, basetype)) - .process_results(|iter| iter.multiunzip())?; - - let out = quote! { - #(#code_masks)* - - #[derive(Debug, Clone, Copy, Default)] - pub struct #upper_camel_name { - inner: #type_ux, - } - - impl #upper_camel_name { - #(#code_getters)* - - #(#code_setters)* - } - impl TryFrom<#type_ux> for #upper_camel_name { - type Error = DataConversionError<#type_ux, Self>; - - fn try_from(value: #type_ux) -> Result { - Ok(Self { inner: value }) - } - } - impl From<#upper_camel_name> for u32 { - fn from(value: #upper_camel_name) -> Self { - value.inner - } - } - }; - - Ok((out, upper_camel_name.clone(), type_ux)) -} - -enum FieldType<'a> { - RustType(RustUxTypes), - CustomValue(&'a [Value]), -} - -/// Generate code for each field, which consists of these three. -/// 1. mask definition -/// 2. getter method -/// 3. setter method -/// -/// # Cases -/// This function is separated into two cases. -/// See each function docs for more detail. -/// -/// 1. field is not "multiple" => [`generate_single_field`] -/// 2. field is "multiple" => [`generate_multiple_field`] -fn generate_field( - field: &Field, - basetype: &DataType, -) -> Result<(TokenStream, TokenStream, TokenStream), CodeGenError> { - let mask_name = util::parse_to_ident(&format!("{}_MASK", field.name.to_shouty_snake_case()))?; - let base_type = util::RustUxTypes::from(basetype).to_rust_type_token(); - - let snake_case_name = util::parse_to_ident(&field.name.to_snake_case())?; - let field_type = match field.elements.is_empty() { - true => FieldType::RustType(util::RustUxTypes::from_mask(field.mask)), - false => FieldType::CustomValue(&field.elements), - }; - - let (code_mask, code_getter, code_setter) = match &field.multiple { - Some(multiple_params) => generate_multiple_field( - mask_name, - base_type, - field.mask, - field_type, - snake_case_name, - multiple_params, - &field.desc.clone().unwrap_or("".to_string()), - ), - None => generate_single_field( - mask_name, - base_type, - field.mask, - field_type, - snake_case_name, - &field.desc.clone().unwrap_or("".to_string()), - ), - }; - - Ok((code_mask, code_getter, code_setter)) -} - -/// Generate "single" field definition (mask, getter, setter). -/// -/// # Cases -/// This function is separated into three cases based on field types [`FieldType`]. -/// -/// - field is `bool` => [`generate_single_bool_field`] -/// - field is `u8`/`u16`/`u32` => [`generate_single_ux_field`] -/// - field is custom [`Value`] => [`generate_custom_values_const_enumdef`] & [`generate_single_custom_values_field`] -/// -/// For the details of types of register/field, see [`DataType`]. -/// Note that in both cases, mask definitions are the same. -fn generate_single_field( - mask_name: Ident, - base_type: Ident, - mask_val: u32, - field_type: FieldType, - snake_case_name: Ident, - desc: &str, -) -> (TokenStream, TokenStream, TokenStream) { - let mask_val = util::parse_to_literal(&format!("0x{:x}", mask_val)).unwrap(); - let code_mask = match field_type { - FieldType::RustType(_) => { - quote! { - const #mask_name: #base_type = #mask_val; - } - } - FieldType::CustomValue(values) => { - let additional = - generate_custom_values_const_enumdef(&base_type, &snake_case_name, values); - quote! { - const #mask_name: #base_type = #mask_val; - #additional - } - } - }; - let (code_getter, code_setter) = match field_type { - FieldType::RustType(field_type) => match field_type { - RustUxTypes::Bool => generate_single_bool_field(mask_name, snake_case_name, desc), - RustUxTypes::U8 | RustUxTypes::U16 | RustUxTypes::U32 => { - generate_single_ux_field(mask_name, base_type, snake_case_name, field_type, desc) - } - }, - FieldType::CustomValue(values) => { - generate_single_custom_values_field(mask_name, snake_case_name, values, desc) - } - }; - - (code_mask, code_getter, code_setter) -} - -/// Generate bool "single" field definition (getter, setter). -fn generate_single_bool_field( - mask_name: Ident, - snake_case_name: Ident, - desc: &str, -) -> (TokenStream, TokenStream) { - let setter_name = util::parse_to_ident(&format!("set_{}", snake_case_name)).unwrap(); - let getter_doc = format!("Getter. {}", desc); - let code_getter = quote! { - #[doc = #getter_doc] - pub fn #snake_case_name(&self) -> bool { - (self.inner & #mask_name) == #mask_name - } - }; - let setter_doc = format!("Setter. {}", desc); - let code_setter = quote! { - #[doc = #setter_doc] - pub fn #setter_name(self, val: bool) -> Self { - let mut inner = self.inner; - if val { - inner |= #mask_name - } else { - inner &= !#mask_name - }; - Self { inner } - } - }; - (code_getter, code_setter) -} - -/// Generate u8/u16/u32 "single" field definition (getter, setter). -fn generate_single_ux_field( - mask_name: Ident, - base_type: Ident, - snake_case_name: Ident, - field_type: RustUxTypes, - desc: &str, -) -> (TokenStream, TokenStream) { - let field_type = field_type.to_rust_type_token(); - let setter_name = util::parse_to_ident(&format!("set_{}", snake_case_name)).unwrap(); - - let getter_doc = format!("Getter. {}", desc); - let code_getter = quote! { - #[doc = #getter_doc] - pub fn #snake_case_name(&self) -> #field_type { - const RIGHT_SHIFT: #base_type = #mask_name.trailing_zeros(); - ((self.inner & #mask_name) >> RIGHT_SHIFT) - .try_into() - .unwrap() - } - }; - let setter_doc = format!("Setter. {}", desc); - let code_setter = quote! { - #[doc = #setter_doc] - pub fn #setter_name(&self, val: #field_type) -> Self { - let update: #base_type = (val as #base_type) & #mask_name; - let mut inner = self.inner; - inner &= !#mask_name; - inner |= update; - Self { inner } - } - }; - (code_getter, code_setter) -} - -fn custom_value_const_name(field_name: &Ident, value_name: &str) -> Ident { - util::parse_to_ident(&format!( - "{}_{}", - field_name.to_string().to_shouty_snake_case(), - value_name.to_shouty_snake_case() - )) - .unwrap() -} - -/// Generate const var and value enum definition. -/// -/// Both for single & multiple. -fn generate_custom_values_const_enumdef( - base_type: &Ident, - field_name: &Ident, - values: &[Value], -) -> TokenStream { - let consts = values.iter().map(|value| { - let const_name = custom_value_const_name(field_name, &value.name); - let val = value.data; - quote! { - const #const_name: #base_type = #val; - } - }); - let variants = values.iter().map(|value| { - let desc = value.desc.clone().unwrap_or("".to_string()); - let variant_name = util::parse_to_ident(&value.name.to_upper_camel_case()).unwrap(); - quote! { - #[doc = #desc] - #variant_name - } - }); - let value_enum_name = - util::parse_to_ident(&field_name.to_string().to_upper_camel_case()).unwrap(); - - quote! { - #(#consts)* - pub enum #value_enum_name { - #(#variants),* - } - } -} - -/// Generate custom [`Value`] "single" field definition (getter, setter). -fn generate_single_custom_values_field( - mask_name: Ident, - snake_case_name: Ident, - values: &[Value], - desc: &str, -) -> (TokenStream, TokenStream) { - let setter_name = util::parse_to_ident(&format!("set_{}", snake_case_name)).unwrap(); - let value_enum_name = - util::parse_to_ident(&snake_case_name.to_string().to_upper_camel_case()).unwrap(); - let (getter_match_arms, setter_match_arms): (Vec<_>, Vec<_>) = values - .iter() - .map(|value| { - let const_name = custom_value_const_name(&snake_case_name, &value.name); - let variant_name = util::parse_to_ident(&value.name.to_upper_camel_case()).unwrap(); - ( - quote! { - #const_name => #value_enum_name::#variant_name - }, - quote! { - #value_enum_name::#variant_name => #const_name - }, - ) - }) - .unzip(); - - let getter_doc = format!("Getter. {}", desc); - let code_getter = quote! { - #[doc = #getter_doc] - pub fn #snake_case_name(&self) -> #value_enum_name { - match (self.inner & #mask_name) - >> #mask_name.trailing_zeros() - { - #(#getter_match_arms),*, - _ => panic!("must not reachable"), - } - } - }; - - let setter_doc = format!("Setter. {}", desc); - let code_setter = quote! { - #[doc = #setter_doc] - pub fn #setter_name(self, val: #value_enum_name) -> Self { - let val = match val { - #(#setter_match_arms),* - }; - let mut inner = self.inner; - inner &= !#mask_name; - inner |= val; - - Self { inner } - } - }; - (code_getter, code_setter) -} - -/// Generate "multiple" field definition (mask, getter, setter). -/// -/// # Cases -/// As "single" field cases, this function is separated into two cases; -/// -/// - fields are `bool` => [`generate_multiple_bool_field`] -/// - fields are `u8`/`u16`/`u32` => [`generate_multiple_ux_field`] -/// - fields are custom [`Value`] => [`generate_custom_values_const_enumdef`] & [`generate_multiple_custom_values_field`] -fn generate_multiple_field( - mask_name: Ident, - base_type: Ident, - single_mask_val: u32, - single_field_type: FieldType, - snake_case_name: Ident, - multiple_params: &MultipleParams, - desc: &str, -) -> (TokenStream, TokenStream, TokenStream) { - let num_multiple = multiple_params.multiple; - let id_num_multiple = util::parse_to_literal(&num_multiple.to_string()).unwrap(); - let masks: Vec<_> = (0..multiple_params.multiple) - .map(|x| x * multiple_params.offset) - .map(|offset| single_mask_val << offset) - .map(|mask| util::parse_to_literal(&format!("0x{mask:x}")).unwrap()) - .collect(); - debug_assert_eq!(masks.len(), num_multiple.try_into().unwrap()); - let value_const_enumdefs = match single_field_type { - FieldType::RustType(_) => quote! {}, - FieldType::CustomValue(values) => { - generate_custom_values_const_enumdef(&base_type, &snake_case_name, values) - } - }; - let code_mask = quote! { - const #mask_name: [#base_type; #id_num_multiple] = [#(#masks),*]; - #value_const_enumdefs - }; - - let (code_getter, code_setter) = match single_field_type { - FieldType::RustType(single_field_type) => match single_field_type { - RustUxTypes::Bool => generate_multiple_bool_field( - mask_name, - base_type, - snake_case_name, - masks.clone(), - desc, - ), - RustUxTypes::U8 | RustUxTypes::U16 | RustUxTypes::U32 => generate_multiple_ux_field( - mask_name, - base_type, - snake_case_name, - single_field_type, - masks, - desc, - ), - }, - FieldType::CustomValue(values) => generate_multiple_custom_values_field( - mask_name, - base_type, - snake_case_name, - masks, - values, - desc, - ), - }; - - (code_mask, code_getter, code_setter) -} - -/// Generate bool "multiple" field definition (getter, setter). -fn generate_multiple_bool_field( - mask_name: Ident, - base_type: Ident, - snake_case_name: Ident, - masks: Vec, - desc: &str, -) -> (TokenStream, TokenStream) { - let num_multiple = masks.len(); - let elem_getter = masks.iter().enumerate().map(|(i, _mask)| { - quote! { - (self.inner & #mask_name[#i]) == #mask_name[#i] - } - }); - let getter_doc = format!("Getter. {}", desc); - let code_getter = quote! { - #[doc = #getter_doc] - pub fn #snake_case_name(&self) -> [bool; #num_multiple] { - [ - #(#elem_getter),* - ] - } - }; - - let setter_name = util::parse_to_ident(&format!("set_{}", snake_case_name)).unwrap(); - let setter_doc = format!("Setter. {}", desc); - let code_setter = quote! { - #[doc = #setter_doc] - pub fn #setter_name(self, val: [bool; #num_multiple]) -> Self { - let mask: #base_type = #mask_name.iter().sum(); - let update: #base_type = #mask_name - .iter() - .zip(val) - .filter_map(|(mask, val)| val.then_some(mask)) - .sum(); - let mut inner = self.inner; - inner &= !mask; - inner |= update; - Self { inner } - } - }; - - (code_getter, code_setter) -} - -/// Generate u8/u16/u32 "multiple" field definition (getter, setter). -fn generate_multiple_ux_field( - mask_name: Ident, - base_type: Ident, - snake_case_name: Ident, - single_field_type: RustUxTypes, - masks: Vec, - desc: &str, -) -> (TokenStream, TokenStream) { - let field_type = single_field_type.to_rust_type_token(); - let num_multiple = masks.len(); - let elem_getter = masks.iter().enumerate().map(|(i, _mask)| { - quote! { - ((self.inner & #mask_name[#i]) - >> (#mask_name[#i].trailing_zeros())) - .try_into() - .unwrap() - } - }); - let getter_doc = format!("Getter. {}", desc); - let code_getter = quote! { - #[doc = #getter_doc] - pub fn #snake_case_name(&self) -> [#field_type; #num_multiple] { - [ - #(#elem_getter),* - ] - } - }; - - let setter_name = util::parse_to_ident(&format!("set_{}", snake_case_name)).unwrap(); - let setter_doc = format!("Setter. {}", desc); - let code_setter = quote! { - #[doc = #setter_doc] - pub fn #setter_name(&self, val: [#field_type; #num_multiple]) -> Self { - let mask: #base_type = #mask_name.iter().sum(); - let update: #base_type = #mask_name - .iter() - .zip(val) - .map(|(mask, val)| (#base_type::from(val)) << (mask.trailing_zeros())) - .sum(); - let mut inner = self.inner; - inner &= !mask; - inner |= update; - Self { inner } - } - }; - - (code_getter, code_setter) -} - -/// Generate custom [`Value`] "single" field definition (getter, setter). -fn generate_multiple_custom_values_field( - mask_name: Ident, - base_type: Ident, - snake_case_name: Ident, - masks: Vec, - values: &[Value], - desc: &str, -) -> (TokenStream, TokenStream) { - let value_enum_name = - util::parse_to_ident(&snake_case_name.to_string().to_upper_camel_case()).unwrap(); - let num_multiple = masks.len(); - let (getter_match_arms, setter_match_arms): (Vec<_>, Vec<_>) = values - .iter() - .map(|value| { - let const_name = custom_value_const_name(&snake_case_name, &value.name); - let variant_name = util::parse_to_ident(&value.name.to_upper_camel_case()).unwrap(); - ( - quote! { - #const_name => #value_enum_name::#variant_name - }, - quote! { - #value_enum_name::#variant_name => #const_name - }, - ) - }) - .unzip(); - - let elem_getter = masks.iter().enumerate().map(|(i, _mask)| { - quote! { - match ((self.inner & #mask_name[#i])) - >> (#mask_name[#i].trailing_zeros()) - { - #(#getter_match_arms),*, - _ => panic!("must not reachable"), - } - } - }); - let getter_doc = format!("Getter. {}", desc); - let code_getter = quote! { - #[doc = #getter_doc] - pub fn #snake_case_name(&self) -> [#value_enum_name; #num_multiple] { - [ - #(#elem_getter),* - ] - } - }; - - let setter_name = util::parse_to_ident(&format!("set_{}", snake_case_name)).unwrap(); - let elem_setter = masks.iter().enumerate().map(|(i, _mask)| { - quote! { - match val[#i] { - #(#setter_match_arms),* - } - } - }); - let setter_doc = format!("Setter. {}", desc); - let code_setter = quote! { - #[doc = #setter_doc] - pub fn #setter_name(&self, val: [#value_enum_name; #num_multiple]) -> Self { - let val: [#base_type; #num_multiple] = [ - #(#elem_setter),* - ]; - let mask: #base_type = #mask_name.iter().sum(); - let update: #base_type = #mask_name - .iter() - .zip(val) - .map(|(mask, val)| (#base_type::from(val)) << (mask.trailing_zeros())) - .sum(); - let mut inner = self.inner; - inner &= !mask; - inner |= update; - Self { inner } - } - }; - - (code_getter, code_setter) -} diff --git a/src/generator/codegen_registerspec_impl.rs b/src/generator/codegen_registerspec_impl.rs deleted file mode 100644 index a1b0edc..0000000 --- a/src/generator/codegen_registerspec_impl.rs +++ /dev/null @@ -1,36 +0,0 @@ -use proc_macro2::{Ident, TokenStream}; -use quote::quote; - -use crate::types::RwSpecifier; - -pub(super) fn gen_registerspec_impl( - reg_name: Ident, - modf: RwSpecifier, - type_t: Ident, - type_ux: Ident, -) -> TokenStream { - let impl_rw = match modf { - RwSpecifier::R => quote! { - impl Readable for #reg_name<'_> {} - }, - RwSpecifier::W => quote! { - impl Writable for #reg_name<'_> {} - }, - RwSpecifier::RW => quote! { - impl Readable for #reg_name<'_> {} - impl Writable for #reg_name<'_> {} - impl Modifiable for #reg_name<'_> {} - }, - }; - quote! { - impl RegisterSpec for #reg_name<'_> { - type Ux = #type_ux; - type T = #type_t; - - fn as_ptr(&self) -> *mut Self::Ux { - self.mem_ptr - } - } - #impl_rw - } -} diff --git a/src/io.rs b/src/io.rs deleted file mode 100644 index fc6ac57..0000000 --- a/src/io.rs +++ /dev/null @@ -1,27 +0,0 @@ -//! File IO for generated codes. - -use std::{collections::HashMap, fs, io, path}; - -/// Write formatted codes generated with [`Module::generate_code`](crate::types::Module::generate_code). -pub fn write_to_files( - files: HashMap, - out_path: &path::Path, -) -> io::Result<()> { - if !out_path.is_dir() { - return Err(io::Error::from(io::ErrorKind::NotADirectory)); - } - if fs::read_dir(out_path)?.next().is_some() { - return Err(io::Error::new( - io::ErrorKind::AlreadyExists, - format!("out path `{}` is not empty", out_path.display()), - )); - } - for (file_path, code) in files { - fs::DirBuilder::new() - .recursive(true) - .create(out_path.join(&file_path).parent().unwrap())?; - - fs::write(out_path.join(&file_path), prettyplease::unparse(&code))?; - } - Ok(()) -} diff --git a/src/lib.rs b/src/lib.rs index e678e80..477c59e 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,53 +1,5 @@ -#![doc = include_str!("../README.md")] -//! -//! ---- -//! -//! _documents in the library_ -//! -//! Generate register interface software from register map in XML. -//! -//! # Example -//! -//! Here's a typical usage: -//! ```no_run -//! use endcap_sl_software_ri_generator::types; -//! -//! let xmlfile = std::fs::read_to_string("./csr.xml")?; -//! let doc = roxmltree::Document::parse_with_options( -//! &xmlfile, -//! roxmltree::ParsingOptions { -//! allow_dtd: true, -//! nodes_limit: u32::MAX, -//! }, -//! )?; -//! -//! let register_map = types::Module::from_xml_dom(doc.root_element())?; -//! -//! let files = register_map.generate_code()?; -//! endcap_sl_software_ri_generator::write_to_files(files, &std::path::PathBuf::from("out"))?; -//! -//! # Ok::<(), anyhow::Error>(()) -//! ``` -//! -//! # Overview -//! -//! 1. Convert [`roxmltree::Document`] to register map represented with types defined in -//! [`types`], filling missing parameters. See [`converter`]. -//! 2. Generate [`proc_macro2::TokenStream`] from register map produced in the previous step. See -//! [`generator`]. -//! -//! # modules -//! - [`types`]: type definitions of internal register map representation -//! - [`converter`]: DOM to internal representation -//! - [`generator`]: internal representation to rust code -//! - [`io`]: formatting and printing +//! Root document [`types::Module::from_xml_dom`] -pub mod converter; -pub mod generator; -pub mod io; -pub mod meta; -mod parser; -mod type_traits; pub mod types; - -pub use io::write_to_files; +pub mod parser; +pub mod converter; diff --git a/src/main.rs b/src/main.rs index c320cef..b042c79 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,27 +1,13 @@ -use std::{fs, path}; +use std::fs; use anyhow::Result; -use clap::Parser; use endcap_sl_software_ri_generator::types; -use itertools::Itertools; - -/// Generate register interface from register map xml. -#[derive(Parser, Debug)] -#[command(version, about)] -struct Args { - /// Input XML register map. - xml: path::PathBuf, - /// Output directory. - out: path::PathBuf, -} fn main() -> Result<()> { env_logger::init(); - log::debug!("logger enabled"); - let args = Args::parse(); - log::debug!("args: {:?}", args); - let xmlfile = fs::read_to_string(args.xml)?; + println!("Hello, world!"); + let xmlfile = fs::read_to_string("./csr.xml")?; let doc = roxmltree::Document::parse_with_options( &xmlfile, roxmltree::ParsingOptions { @@ -29,27 +15,11 @@ fn main() -> Result<()> { nodes_limit: u32::MAX, }, )?; - log::debug!("Parsed: {:#?}", doc); + // println!("Parsed: {:#?}", doc); + // println!("Root: {:?}", doc.root_element()); let register_map = types::Module::from_xml_dom(doc.root_element())?; - log::info!("read: {:?}", register_map); - log::debug!("read: {:#?}", register_map); - - let files = register_map.generate_code()?; - if log::log_enabled!(log::Level::Debug) { - for (path, code) in &files { - log::debug!("path: {:?}", path); - log::debug!("{}", prettyplease::unparse(code)); - log::trace!("{}", prettyplease::unparse(code)); - } - } - if log::log_enabled!(log::Level::Info) { - for filepath in files.keys().sorted() { - log::info!("{}", filepath.display()); - } - } - - endcap_sl_software_ri_generator::write_to_files(files, &args.out)?; + println!("read: {:#?}", register_map); Ok(()) } diff --git a/src/meta.rs b/src/meta.rs deleted file mode 100644 index 56a7156..0000000 --- a/src/meta.rs +++ /dev/null @@ -1,13 +0,0 @@ -//! Get build metadata at compile time. -//! -//! See build.rs for more detail. - -pub(crate) const GENERATOR_BUILD_TIMESTAMP: &str = - env!("VERGEN_BUILD_TIMESTAMP", "Failed to get build timestamp"); -pub(crate) const GENERATOR_GIT_DESCRIBE: &str = - env!("VERGEN_GIT_DESCRIBE", "Failed to get git describe"); -pub(crate) const GENERATOR_GIT_COMMIT_TIMESTAMP: &str = env!( - "VERGEN_GIT_COMMIT_TIMESTAMP", - "Failed to get git commit timestamp" -); -pub(crate) const GENERATOR_GIT_SHA: &str = env!("VERGEN_GIT_SHA", "Failed to get git sha"); diff --git a/src/parser.rs b/src/parser.rs index 87e86f9..41882ef 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -1,6 +1,4 @@ //! Module for converting XML custom token string to rust types. -//! -//! Unlike, [`crate::converter`], this only has string "parser". use std::any; diff --git a/src/type_traits.rs b/src/type_traits.rs deleted file mode 100644 index d68da02..0000000 --- a/src/type_traits.rs +++ /dev/null @@ -1,30 +0,0 @@ -//! Util traits to get info from types in [`crate::types`]. - -use crate::types::{Block, ModuleBlockElements, Register}; - -pub(crate) trait GetName { - fn get_name(&self) -> String; -} - -impl GetName for ModuleBlockElements { - fn get_name(&self) -> String { - match self { - ModuleBlockElements::Block(block) => block.get_name(), - ModuleBlockElements::Register(register) => register.get_name(), - ModuleBlockElements::Memory(_memory) => todo!(), - ModuleBlockElements::Fifo(_fifo) => todo!(), - } - } -} - -impl GetName for Block { - fn get_name(&self) -> String { - self.name.clone() - } -} - -impl GetName for Register { - fn get_name(&self) -> String { - self.name.clone() - } -} diff --git a/src/types.rs b/src/types.rs index e074786..fa4ba30 100644 --- a/src/types.rs +++ b/src/types.rs @@ -1,5 +1,3 @@ -//! Register type definition. - #[derive(Debug)] pub struct Module { pub name: String, @@ -10,7 +8,6 @@ pub struct Module { pub desc: Option, pub elements_bitstring: Vec, pub elements_other: Vec, - pub xmlhash: [u8; 32], } #[derive(Debug)] @@ -54,8 +51,6 @@ pub struct Register { pub name: String, /// Fill this with proper calc. pub addr: u32, - /// Fill this with proper calc. - pub r#type: DataType, pub mask: Option, /// Fill this with proper calc. pub modf: RwSpecifier, @@ -114,7 +109,7 @@ pub struct Field { pub struct Value { pub name: String, pub data: u32, - pub desc: Option, + pub desc: Option } #[derive(Debug, PartialEq)] @@ -127,7 +122,7 @@ pub enum AmodValues { USER2, } -#[derive(Debug, Clone, Copy)] +#[derive(Debug)] pub enum DataType { D32, }