diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..085392a --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,48 @@ +name: CI + +on: + push: + branches: + - master + pull_request: + +jobs: + build_and_test: + name: Build and test + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v1 + - uses: actions-rs/toolchain@v1 + with: + toolchain: stable + override: true + - name: Run tests + uses: actions-rs/cargo@v1 + with: + command: test + args: --all-features + clippy: + name: Clippy + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v1 + - uses: actions-rs/toolchain@v1 + with: + toolchain: stable + components: clippy + override: true + - uses: actions-rs/clippy-check@v1 + with: + token: ${{ secrets.GITHUB_TOKEN }} + args: --all-features + rustfmt: + name: Rustfmt + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v1 + - uses: actions-rs/toolchain@v1 + with: + toolchain: stable + components: rustfmt + override: true + - run: cargo fmt -- --check diff --git a/Cargo.lock b/Cargo.lock index 68a2b10..3891c71 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1,46 +1,94 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. [[package]] name = "aho-corasick" -version = "0.6.9" +version = "0.7.8" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "memchr 2.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "memchr 2.3.2 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "alphanumeric-sort" -version = "1.0.6" +version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "ansi_term" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "atty" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "hermit-abi 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "bitflags" version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "bitflags" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "cfg-if" -version = "0.1.6" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "clap" +version = "2.33.0" source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", + "atty 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)", + "bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "strsim 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", + "textwrap 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", + "unicode-width 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", + "vec_map 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", +] [[package]] name = "cube-parse" version = "0.1.0" dependencies = [ - "alphanumeric-sort 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "regex 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.84 (registry+https://github.com/rust-lang/crates.io-index)", + "alphanumeric-sort 1.0.11 (registry+https://github.com/rust-lang/crates.io-index)", + "clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "regex 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)", "serde-xml-rs 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.84 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "hermit-abi" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "lazy_static" -version = "1.2.0" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "libc" -version = "0.2.45" +version = "0.2.66" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -48,66 +96,57 @@ name = "log" version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "log" -version = "0.4.6" +version = "0.4.8" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "memchr" -version = "2.1.2" +version = "2.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.45 (registry+https://github.com/rust-lang/crates.io-index)", - "version_check 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", -] [[package]] name = "proc-macro2" -version = "0.4.24" +version = "1.0.8" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "quote" -version = "0.6.10" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro2 0.4.24 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "regex" -version = "1.1.0" +version = "1.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "aho-corasick 0.6.9 (registry+https://github.com/rust-lang/crates.io-index)", - "memchr 2.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "regex-syntax 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)", - "thread_local 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", - "utf8-ranges 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "aho-corasick 0.7.8 (registry+https://github.com/rust-lang/crates.io-index)", + "memchr 2.3.2 (registry+https://github.com/rust-lang/crates.io-index)", + "regex-syntax 0.6.14 (registry+https://github.com/rust-lang/crates.io-index)", + "thread_local 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "regex-syntax" -version = "0.6.4" +version = "0.6.14" source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "ucd-util 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", -] [[package]] name = "serde" -version = "1.0.84" +version = "1.0.104" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -116,56 +155,83 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.84 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)", "xml-rs 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "serde_derive" -version = "1.0.84" +version = "1.0.104" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro2 0.4.24 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.15.23 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.14 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "strsim" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "syn" -version = "0.15.23" +version = "1.0.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "proc-macro2 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "textwrap" +version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro2 0.4.24 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)", - "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "unicode-width 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "thread_local" -version = "0.3.6" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] -name = "ucd-util" -version = "0.1.3" +name = "unicode-width" +version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "unicode-xid" -version = "0.1.0" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] -name = "utf8-ranges" -version = "1.0.2" +name = "vec_map" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "winapi" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] -name = "version_check" -version = "0.1.5" +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -177,26 +243,35 @@ dependencies = [ ] [metadata] -"checksum aho-corasick 0.6.9 (registry+https://github.com/rust-lang/crates.io-index)" = "1e9a933f4e58658d7b12defcf96dc5c720f20832deebe3e0a19efd3b6aaeeb9e" -"checksum alphanumeric-sort 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "7cd2580c95c654d681db0194a310af67a293f5e1c8bafa5b35b63269c4665a39" +"checksum aho-corasick 0.7.8 (registry+https://github.com/rust-lang/crates.io-index)" = "743ad5a418686aad3b87fd14c43badd828cf26e214a00f92a384291cf22e1811" +"checksum alphanumeric-sort 1.0.11 (registry+https://github.com/rust-lang/crates.io-index)" = "f37ce94154d73f6961f87571a3ab7814e1608f373bd55a933e3e771b6dd59fc4" +"checksum ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b" +"checksum atty 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)" = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" "checksum bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "aad18937a628ec6abcd26d1489012cc0e18c21798210f491af69ded9b881106d" -"checksum cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "082bb9b28e00d3c9d39cc03e64ce4cea0f1bb9b3fde493f0cbc008472d22bdf4" -"checksum lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a374c89b9db55895453a74c1e38861d9deec0b01b405a82516e9d5de4820dea1" -"checksum libc 0.2.45 (registry+https://github.com/rust-lang/crates.io-index)" = "2d2857ec59fadc0773853c664d2d18e7198e83883e7060b63c924cb077bd5c74" +"checksum bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" +"checksum cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" +"checksum clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5067f5bb2d80ef5d68b4c87db81601f0b75bca627bc2ef76b141d7b846a3c6d9" +"checksum hermit-abi 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "e2c55f143919fbc0bc77e427fe2d74cf23786d7c1875666f2fde3ac3c659bb67" +"checksum lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" +"checksum libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)" = "d515b1f41455adea1313a4a2ac8a8a477634fbae63cc6100e3aebb207ce61558" "checksum log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "e19e8d5c34a3e0e2223db8e060f9e8264aeeb5c5fc64a4ee9965c062211c024b" -"checksum log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c84ec4b527950aa83a329754b01dbe3f58361d1c5efacd1f6d68c494d08a17c6" -"checksum memchr 2.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "db4c41318937f6e76648f42826b1d9ade5c09cafb5aef7e351240a70f39206e9" -"checksum proc-macro2 0.4.24 (registry+https://github.com/rust-lang/crates.io-index)" = "77619697826f31a02ae974457af0b29b723e5619e113e9397b8b82c6bd253f09" -"checksum quote 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)" = "53fa22a1994bd0f9372d7a816207d8a2677ad0325b073f5c5332760f0fb62b5c" -"checksum regex 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "37e7cbbd370869ce2e8dff25c7018702d10b21a20ef7135316f8daecd6c25b7f" -"checksum regex-syntax 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)" = "4e47a2ed29da7a9e1960e1639e7a982e6edc6d49be308a3b02daf511504a16d1" -"checksum serde 1.0.84 (registry+https://github.com/rust-lang/crates.io-index)" = "0e732ed5a5592c17d961555e3b552985baf98d50ce418b7b655f31f6ba7eb1b7" +"checksum log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)" = "14b6052be84e6b71ab17edffc2eeabf5c2c3ae1fdb464aae35ac50c67a44e1f7" +"checksum memchr 2.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "53445de381a1f436797497c61d851644d0e8e88e6140f22872ad33a704933978" +"checksum proc-macro2 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)" = "3acb317c6ff86a4e579dfa00fc5e6cca91ecbb4e7eb2df0468805b674eb88548" +"checksum quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "053a8c8bcc71fcce321828dc897a98ab9760bef03a4fc36693c231e5b3216cfe" +"checksum regex 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "322cf97724bea3ee221b78fe25ac9c46114ebb51747ad5babd51a2fc6a8235a8" +"checksum regex-syntax 0.6.14 (registry+https://github.com/rust-lang/crates.io-index)" = "b28dfe3fe9badec5dbf0a79a9cccad2cfc2ab5484bdb3e44cbd1ae8b3ba2be06" +"checksum serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)" = "414115f25f818d7dfccec8ee535d76949ae78584fc4f79a6f45a904bf8ab4449" "checksum serde-xml-rs 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0c06881f4313eec67d4ecfcd8e14339f6042cfc0de4b1bd3ceae74c29d597f68" -"checksum serde_derive 1.0.84 (registry+https://github.com/rust-lang/crates.io-index)" = "b4d6115a3ca25c224e409185325afc16a0d5aaaabc15c42b09587d6f1ba39a5b" -"checksum syn 0.15.23 (registry+https://github.com/rust-lang/crates.io-index)" = "9545a6a093a3f0bd59adb472700acc08cad3776f860f16a897dfce8c88721cbc" -"checksum thread_local 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c6b53e329000edc2b34dbe8545fd20e55a333362d0a321909685a19bd28c3f1b" -"checksum ucd-util 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "535c204ee4d8434478593480b8f86ab45ec9aae0e83c568ca81abf0fd0e88f86" -"checksum unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc" -"checksum utf8-ranges 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "796f7e48bef87609f7ade7e06495a87d5cd06c7866e6a5cbfceffc558a243737" -"checksum version_check 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "914b1a6776c4c929a602fafd8bc742e06365d4bcbe48c30f9cca5824f70dc9dd" +"checksum serde_derive 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)" = "128f9e303a5a29922045a830221b8f78ec74a5f544944f3d5984f8ec3895ef64" +"checksum strsim 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a" +"checksum syn 1.0.14 (registry+https://github.com/rust-lang/crates.io-index)" = "af6f3550d8dff9ef7dc34d384ac6f107e5d31c8f57d9f28e0081503f547ac8f5" +"checksum textwrap 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060" +"checksum thread_local 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d40c6d1b69745a6ec6fb1ca717914848da4b44ae29d9b3080cbee91d72a69b14" +"checksum unicode-width 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "caaa9d531767d1ff2150b9332433f32a24622147e5ebb1f26409d5da67afd479" +"checksum unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "826e7639553986605ec5979c7dd957c7895e93eabed50ab2ffa7f6128a75097c" +"checksum vec_map 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "05c78687fb1a80548ae3250346c3db86a80a7cdd77bda190189f2d0a0987c81a" +"checksum winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)" = "8093091eeb260906a183e6ae1abdba2ef5ef2257a21801128899c3fc699229c6" +"checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" +"checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" "checksum xml-rs 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "7ec6c39eaa68382c8e31e35239402c0a9489d4141a8ceb0c716099a0b515b562" diff --git a/Cargo.toml b/Cargo.toml index 1de95d2..506f91c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,13 +1,14 @@ [package] name = "cube-parse" version = "0.1.0" -authors = ["HarkonenBade"] +authors = ["HarkonenBade", "Danilo Bargen "] edition = "2018" [dependencies] +clap = "2" serde = "1.0" serde-xml-rs = "0.2" serde_derive = "1.0" regex = "1.1" lazy_static = "1.2" -alphanumeric-sort = "1.0" \ No newline at end of file +alphanumeric-sort = "1.0" diff --git a/README.md b/README.md index ce049f1..9e9e22c 100644 --- a/README.md +++ b/README.md @@ -1,9 +1,217 @@ # Cube Parser -A program to extract AF modes on MCU pins from the database files provided with STM32CubeMX. +[![Build Status][github-actions-badge]][github-actions] + +A program to extract hardware configuration information from the MCU database +files shipped with STM32CubeMX. + ## Usage + + cargo run features STM32L0 -d /path/to/stm32cubemx/db/mcu/ + cargo run pin_mappings STM32L0 -d /path/to/stm32cubemx/db/mcu/ + +Under a default Windows install, the database path is `C:\Program Files +(x86)\STMicroelectronics\STM32Cube\STM32CubeMX\db\mcu`, adjust as appropriate +for your local config. The MCU family name should match one of the MCU families +as defined in `families.xml`. At the time of writing, the following families +are available: + +* STM32F0 +* STM32F1 +* STM32F2 +* STM32F3 +* STM32F4 +* STM32F7 +* STM32G0 +* STM32G4 +* STM32H7 +* STM32L0 +* STM32L1 +* STM32L4 +* STM32L4+ +* STM32L5 +* STM32MP1 +* STM32WB + + +## The STM32CubeMX Database + +The STM32CubeMX database contains the following files that are relevant to us: + +### Families + +In the root, there is a file called `families.xml`. It contains all MCUs +grouped by family (e.g. "STM32F0") and subfamily (e.g. "STM32F0x0 Value Line"). + +```xml + + + + + Arm Cortex-M0 + 48 + 4 + ... + + + ... ``` -cargo run $PATH_TO_MCU_DB_DIR $NAME_OF_MCU_FAMILY + +### MCU + +Next to the `families.xml` file, there are a lot of MCU definitions. The +filenames match the `Name` attribute in the `Mcu` element above. + +For example, the `STM32L071KB(B-Z)Tx.xml` file starts like this: + +```xml + + Arm Cortex-M0+ + 32 + 6144 + 20 + 25 + DIE447 + 128 + 192 + + + + ... ``` -Under a default windows install `$PATH_TO_MCU_DB_DIR` is `C:\Program Files (x86)\STMicroelectronics\STM32Cube\STM32CubeMX\db\mcu`, adjust as appropriate for your local config. The MCU family name should match one of the MCU families as defined in `families.xml`. The program will output one AF mode definition per GPIO variant, with cfg feature gates for the different MCU variants that utalise that GPIO type. \ No newline at end of file + +This first part describes the MCU: How much RAM it has, what the frequency is, +how many I/Os it has, what flash variants there are, etc. Many of these things +are also encoded in the full MCU `RefName`. + +Following this general description, there are a number of `IP` elements. IP +stands for "Internal Peripheral". Here we have things like the USART peripherals: + +```xml + + +``` + +...or the RCC peripheral: + +```xml + +``` + +...and, most important to us, the GPIO peripheral. + +```xml + +``` + +Here, the value of the `Version` attribute points to the actual GPIO signal +definition. + +(There are also some other interesting entries in that file, for example the +mapping from physical pins to internal pin names. Those are not relevant for us +though.) + +### GPIO Internal Peripheral + +The GPIO IP can be found in the `IP` directory. The relevant file for us is at +`IP/GPIO-_Modes.xml`. The version can be extracted from the `IP` +element shown in the previous section. + +In the case of the `STM32L071KBTx`, the relevant GPIO IP version file is at +`IP/GPIO-STM32L071_gpio_v1_0_Modes.xml`. + +That file starts out with some `RefParameter` and `RefMode` elements. Relevant +to us are mostly the `GPIO_Pin` elements. They look like this: + +```xml + + + GPIO_PIN_6 + + + + GPIO_AF1_I2C1 + + + + + GPIO_AF2_LPTIM1 + + + + + GPIO_AF3_TSC + + + + + GPIO_AF0_USART1 + + + +``` + +As you can see, this element describes the pin `PB6`. Depending on the chosen +Alternative Function (AF), it can become an `I2C1_SCL` pin (AF1), a `USART1_TX` +pin (AF0), or some other variants. + + +## GPIO Feature Groups + +When generating pin function mappings, we want to avoid generating a mapping +for every possible MCU, since that would result in dozens or even hundreds of +pin definitions. However, if we don't want a mapping per MCU, we need to group +them somehow. The best way for grouping is probably to follow ST's grouping, +which is encoded in the IP versions described above. + +The feature names are mapped as follows: + +- `STM32L031_gpio_v1_0` -> `io-STM32L031` +- `STM32L051_gpio_v1_0` -> `io-STM32L051` +- `STM32L152x8_gpio_v1_0` -> `io-STM32L152x8` + +For example, the GPIO IP file named "STM32L031_gpio_v1_0" is shared among the +following MCUs: + +- STM32L010C6Tx +- STM32L031C(4-6)Tx +- STM32L031C(4-6)Tx +- STM32L031C6Ux +- STM32L031E(4-6)Yx +- STM32L031E(4-6)Yx +- STM32L031F(4-6)Px +- STM32L031F(4-6)Px +- STM32L031G(4-6)Ux +- STM32L031G(4-6)Ux +- STM32L031G6UxS +- STM32L031K(4-6)Tx +- STM32L031K(4-6)Tx +- STM32L031K(4-6)Ux +- STM32L031K(4-6)Ux +- STM32L041C(4-6)Tx +- STM32L041C(4-6)Tx +- STM32L041E6Yx +- STM32L041F6Px +- STM32L041G6Ux +- STM32L041G6UxS +- STM32L041K6Tx +- STM32L041K6Ux + +As you can see, this may be a bit confusing due to the fact that both the +`STM32L010C6Tx` and the `STM32L041E6Yx` require the `io-STM32L031` feature. +However, sticking to the (sometimes non-logical) grouping used in the CubeMX +database is probably still better than creating our own grouping, which may be +broken at any time by ST releasing a new MCU in a pre-existing group, but with +a different, incompatible GPIO IP version. + +In order to simplify the GPIO IP version selection for the user, alias features +are generated. These are purely a convenience for the user and are never used +directly as feature gates in the source code. + + + +[github-actions]: https://github.com/dbrgn/cube-parse/actions?query=branch%3Amaster +[github-actions-badge]: https://github.com/dbrgn/cube-parse/workflows/CI/badge.svg diff --git a/src/family.rs b/src/family.rs index 4721bde..d8e6fcf 100644 --- a/src/family.rs +++ b/src/family.rs @@ -1,6 +1,6 @@ +use std::error::Error; use std::path::Path; -use serde; use serde_derive::Deserialize; use crate::utils::load_file; @@ -8,36 +8,79 @@ use crate::utils::load_file; #[derive(Debug, Deserialize)] #[serde(rename_all = "PascalCase")] pub struct Families { - #[serde(rename="Family")] + #[serde(rename = "Family")] families: Vec, } +/// A MCU family (e.g. "STM32F0" or "STM32L3"). #[derive(Debug, Deserialize)] #[serde(rename_all = "PascalCase")] pub struct Family { pub name: String, - #[serde(rename="SubFamily")] + #[serde(rename = "SubFamily")] sub_families: Vec, } +/// A MCU subfamily (e.g. "STM32F0x0 Value Line"). #[derive(Debug, Deserialize)] #[serde(rename_all = "PascalCase")] pub struct SubFamily { pub name: String, - #[serde(rename="Mcu")] - mcus: Vec, + #[serde(rename = "Mcu")] + pub mcus: Vec, } +/// A MCU (e.g. STM32L071KBTx). +/// +/// Note that multiple MCUs (with unique `ref_name`) share a common name. For +/// example: +/// +/// - `` +/// - `` +/// +/// Both MCUs share the same name, but the ref name is different. +/// +/// The meaning of the name, using the `STM32L071KBTx` as an example: +/// +/// |Part |Meaning | +/// |-----|--------| +/// |STM32|Family | +/// | L |Type | +/// | 0 |Core | +/// | 71 |Line | +/// | K |Pincount| +/// | B |Flash | +/// | T |Package | +/// | x |Temp | +/// |-----|--------| +/// +/// See https://ziutek.github.io/2018/05/07/stm32_naming_scheme.html for more details. +/// +/// Note that sometimes there are exceptions from this naming rule. #[derive(Debug, Deserialize)] #[serde(rename_all = "PascalCase")] pub struct Mcu { pub name: String, - package_name: String, - ref_name: String, + pub package_name: String, + pub ref_name: String, + #[serde(rename = "Flash")] + pub flash_size: String, + #[serde(rename = "Ram")] + pub ram_size: String, +} + +impl Mcu { + pub fn flash_size(&self) -> Option { + self.flash_size.parse().ok() + } + + pub fn ram_size(&self) -> Option { + self.ram_size.parse().ok() + } } impl Families { - pub fn load>(db_dir: P) -> Result> { + pub fn load>(db_dir: P) -> Result> { load_file(db_dir, "families.xml") } } @@ -67,4 +110,4 @@ impl<'a> IntoIterator for &'a SubFamily { fn into_iter(self) -> ::IntoIter { self.mcus.iter() } -} \ No newline at end of file +} diff --git a/src/internal_peripheral.rs b/src/internal_peripheral.rs index 12faa9a..e0c5944 100644 --- a/src/internal_peripheral.rs +++ b/src/internal_peripheral.rs @@ -1,8 +1,8 @@ +use std::error::Error; use std::path::Path; use lazy_static::lazy_static; use regex::Regex; -use serde; use serde_derive::Deserialize; use crate::utils::load_file; @@ -47,21 +47,21 @@ pub struct GPIOPin { } #[derive(Debug, Deserialize)] -#[serde(rename="IP")] +#[serde(rename = "IP")] pub struct IpGPIO { #[serde(rename = "GPIO_Pin")] pub(crate) gpio_pin: Vec, } impl IpGPIO { - pub fn load>(db_dir: P, version: &str) -> Result> { + pub fn load>(db_dir: P, version: &str) -> Result> { load_file(db_dir, format!("IP/GPIO-{}_Modes.xml", version)) } } lazy_static! { - static ref USART_RX: Regex = Regex::new("USART._RX").unwrap(); - static ref USART_TX: Regex = Regex::new("USART._TX").unwrap(); + static ref USART_RX: Regex = Regex::new("(LP)?US?ART._RX").unwrap(); + static ref USART_TX: Regex = Regex::new("(LP)?US?ART._TX").unwrap(); static ref SPI_MOSI: Regex = Regex::new("SPI._MOSI").unwrap(); static ref SPI_MISO: Regex = Regex::new("SPI._MISO").unwrap(); static ref SPI_SCK: Regex = Regex::new("SPI._SCK").unwrap(); diff --git a/src/main.rs b/src/main.rs index 98257a7..2b29373 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,13 +1,383 @@ use std::{collections::HashMap, env, path::Path}; use alphanumeric_sort::compare_str; -use serde_xml_rs; +use clap::{App, Arg}; +use lazy_static::lazy_static; +use regex::Regex; mod family; mod internal_peripheral; mod mcu; mod utils; +#[derive(Debug, PartialEq)] +enum GenerateTarget { + Features, + PinMappings, + EepromSizes, +} + +lazy_static! { + // Note: Version >1.0 is not currently supported + static ref GPIO_VERSION: Regex = Regex::new("^([^_]*)_gpio_v1_0$").unwrap(); +} + +/// Convert a GPIO IP version (e.g. "STM32L152x8_gpio_v1_0") to a feature name +/// (e.g. "io-STM32L152x8"). +fn gpio_version_to_feature(version: &str) -> Result { + if let Some(captures) = GPIO_VERSION.captures(version) { + Ok(format!("io-{}", captures.get(1).unwrap().as_str())) + } else { + Err(format!("Could not parse version {:?}", version)) + } +} + +/// Get the EEPROM size feature for a certain size. +fn eeprom_size_to_feature(size: u32) -> String { + format!("eeprom-{}", size) +} + +/// Get the Flash size feature for a certain size. +fn flash_size_to_feature(size: u32) -> String { + format!("flash-{}", size) +} + +/// Get the RAM size feature for a certain size. +fn ram_size_to_feature(size: u32) -> String { + format!("ram-{}", size) +} + +fn main() -> Result<(), String> { + let args = App::new("cube-parse") + .version(env!("CARGO_PKG_VERSION")) + .about("Extract AF modes on MCU pins from the database files provided with STM32CubeMX") + .author(&*env!("CARGO_PKG_AUTHORS").replace(":", ", ")) + .arg( + Arg::with_name("db_dir") + .short("d") + .help("Path to the CubeMX MCU database directory") + .takes_value(true) + .required(true), + ) + .arg( + Arg::with_name("generate") + .help("What to generate") + .takes_value(true) + .possible_values(&["features", "pin_mappings", "eeprom_sizes"]) + .required(true), + ) + .arg( + Arg::with_name("mcu_family") + .help("The MCU family to extract, e.g. \"STM32L0\"") + .takes_value(true) + .required(true), + ) + .get_matches(); + + // Process args + let db_dir = Path::new(args.value_of("db_dir").unwrap()); + let mcu_family = args.value_of("mcu_family").unwrap(); + let generate = match args.value_of("generate").unwrap() { + "features" => GenerateTarget::Features, + "pin_mappings" => GenerateTarget::PinMappings, + "eeprom_sizes" => GenerateTarget::EepromSizes, + _ => unreachable!(), + }; + + // Load families + let families = family::Families::load(&db_dir) + .map_err(|e| format!("Could not load families XML: {}", e))?; + + // Find target family + let family = (&families) + .into_iter() + .find(|v| v.name == mcu_family) + .ok_or_else(|| format!("Could not find family {}", mcu_family))?; + + // MCU map + // + // This maps a MCU ref name to the corresponding `mcu::Mcu` instance. + let mut mcu_map: HashMap = HashMap::new(); + + // GPIO map + // + // The keys of this map are GPIO peripheral version strings (e.g. + // "STM32L051_gpio_v1_0"), while the value is a Vec of MCU ref names. + let mut mcu_gpio_map: HashMap> = HashMap::new(); + + // Package map + // + // The keys of this map are MCU ref names, the values are package names. + let mut mcu_package_map: HashMap = HashMap::new(); + + // EEPROM size map + // + // The keys of this map are EEPROM sizes, the values are Vecs of MCU ref names. + let mut mcu_eeprom_size_map: HashMap> = HashMap::new(); + + // Flash size map + // + // The keys of this map are flash sizes, the values are Vecs of MCU ref names. + let mut mcu_flash_size_map: HashMap> = HashMap::new(); + + // RAM size map + // + // The keys of this map are RAM sizes, the values are Vecs of MCU ref names. + let mut mcu_ram_size_map: HashMap> = HashMap::new(); + + // Iterate through subfamilies, then through MCUs. Fill the maps above with + // aggregated data. + for sf in family { + for mcu in sf { + // Load MCU data from the XML files + let mcu_dat = mcu::Mcu::load(&db_dir, &mcu.name) + .map_err(|e| format!("Could not load MCU data for mcu {}: {}", &mcu.name, e))?; + + // Fill GPIO map + let gpio_version = mcu_dat.get_ip("GPIO").unwrap().get_version().to_string(); + mcu_gpio_map + .entry(gpio_version) + .or_insert(vec![]) + .push(mcu.ref_name.clone()); + + // Fill package map + if mcu_family == "STM32L0" { + // The stm32l0xx-hal has package based features + mcu_package_map.insert(mcu.ref_name.clone(), mcu.package_name.clone()); + } + + // Fill EEPROM size map + if let Some(size) = mcu_dat.get_eeprom_size() { + mcu_eeprom_size_map + .entry(size) + .or_insert(vec![]) + .push(mcu.ref_name.clone()); + } + + // Fill flash size map + if let Some(flash_size) = mcu.flash_size() { + mcu_flash_size_map + .entry(flash_size) + .or_insert(vec![]) + .push(mcu.ref_name.clone()); + } + + // Fill RAM size map + if let Some(ram_size) = mcu.ram_size() { + mcu_ram_size_map + .entry(ram_size) + .or_insert(vec![]) + .push(mcu.ref_name.clone()); + } + + mcu_map.insert(mcu.ref_name.clone(), (mcu, mcu_dat)); + } + } + + match generate { + GenerateTarget::Features => generate_features( + &mcu_map, + &mcu_gpio_map, + &mcu_package_map, + &mcu_eeprom_size_map, + &mcu_flash_size_map, + &mcu_ram_size_map, + &mcu_family, + )?, + GenerateTarget::PinMappings => generate_pin_mappings(&mcu_gpio_map, &db_dir)?, + GenerateTarget::EepromSizes => generate_eeprom_sizes(&mcu_eeprom_size_map)?, + }; + + Ok(()) +} + +lazy_static! { + static ref FEATURE_DEPENDENCIES: HashMap<&'static str, HashMap<&'static str, &'static str>> = { + let mut m = HashMap::new(); + + // STM32L0 + let mut l0 = HashMap::new(); + l0.insert("^STM32L0.1", "stm32l0x1"); + l0.insert("^STM32L0.2", "stm32l0x2"); + l0.insert("^STM32L0.3", "stm32l0x3"); + m.insert("STM32L0", l0); + + m + }; +} + +/// Generate all Cargo features +/// +/// Feature categories: +/// +/// - IO features (`io-*`) +/// - EEPROM features (`eeprom-*`) +/// +/// Finally, the MCU features are printed, they act purely as aliases for the +/// other features. +fn generate_features( + mcu_map: &HashMap, + mcu_gpio_map: &HashMap>, + mcu_package_map: &HashMap, + mcu_eeprom_size_map: &HashMap>, + mcu_flash_size_map: &HashMap>, + mcu_ram_size_map: &HashMap>, + mcu_family: &str, +) -> Result<(), String> { + // IO features + let mut io_features = mcu_gpio_map + .keys() + .map(|gpio| gpio_version_to_feature(gpio)) + .collect::, String>>()?; + io_features.sort(); + println!("# Features based on the GPIO peripheral version"); + println!("# This determines the pin function mapping of the MCU"); + for feature in io_features { + println!("{} = []", feature); + } + println!(); + + // EEPROM sizes + let mut eeprom_sizes = mcu_eeprom_size_map.keys().collect::>(); + eeprom_sizes.sort(); + println!("# Features based on EEPROM size (in bytes)"); + for size in eeprom_sizes { + println!("{} = []", eeprom_size_to_feature(*size)); + } + println!(); + + // Flash sizes + let mut flash_sizes = mcu_flash_size_map.keys().collect::>(); + flash_sizes.sort(); + println!("# Features based on Flash size (in kbytes)"); + for size in flash_sizes { + println!("{} = []", flash_size_to_feature(*size)); + } + println!(); + + // RAM sizes + let mut ram_sizes = mcu_ram_size_map.keys().collect::>(); + ram_sizes.sort(); + println!("# Features based on RAM size (in kbytes)"); + for size in ram_sizes { + println!("{} = []", ram_size_to_feature(*size)); + } + println!(); + + // Physical packages + if !mcu_package_map.is_empty() { + println!("# Physical packages"); + let mut packages = mcu_package_map + .values() + .map(|v| v.to_lowercase()) + .collect::>(); + packages.sort_by(|a, b| compare_str(a, b)); + packages.dedup(); + for pkg in packages { + println!("{} = []", pkg); + } + println!(); + } + + // MCU features + let mut mcu_aliases = vec![]; + for (gpio, mcu_list) in mcu_gpio_map { + let gpio_version_feature = gpio_version_to_feature(gpio).unwrap(); + for mcu in mcu_list { + let mut dependencies = vec![]; + + // Static feature dependencies + if let Some(family) = FEATURE_DEPENDENCIES.get(mcu_family) { + for (pattern, feature) in family { + if Regex::new(pattern).unwrap().is_match(&mcu) { + dependencies.push(feature.to_string()); + break; + } + } + } + + // Package based feature + if let Some(package) = mcu_package_map.get(mcu) { + dependencies.push(package.to_lowercase()); + } + + // GPIO version feature + dependencies.push(gpio_version_feature.clone()); + + let (mcu_info, mcu_dat) = mcu_map.get(mcu).unwrap(); + + // EEPROM size + if let Some(size) = mcu_dat.get_eeprom_size() { + dependencies.push(eeprom_size_to_feature(size)); + } + + // Flash & RAM size + if let Some(flash_size) = mcu_info.flash_size() { + dependencies.push(flash_size_to_feature(flash_size)); + } + + if let Some(ram_size) = mcu_info.ram_size() { + dependencies.push(ram_size_to_feature(ram_size)); + } + + mcu_aliases.push(format!( + "mcu-{} = [{}]", + mcu, + &dependencies.iter().map(|val| format!("\"{}\"", val)).fold( + String::new(), + |mut acc, x| { + if !acc.is_empty() { + acc.push_str(", "); + } + acc.push_str(&x); + acc + } + ) + )); + } + } + mcu_aliases.sort(); + println!("# MCU aliases"); + println!("#"); + println!("# Note: These are just aliases, they should not be used to directly feature gate"); + println!( + "# functionality in the HAL! However, user code should usually depend on a MCU alias." + ); + for alias in mcu_aliases { + println!("{}", alias); + } + + Ok(()) +} + +/// Generate the pin mappings for the target MCU family. +fn generate_pin_mappings( + mcu_gpio_map: &HashMap>, + db_dir: &Path, +) -> Result<(), String> { + let mut gpio_versions = mcu_gpio_map.keys().collect::>(); + gpio_versions.sort(); + for gpio in gpio_versions { + let gpio_version_feature = gpio_version_to_feature(&gpio)?; + println!("#[cfg(feature = \"{}\")]", gpio_version_feature); + let gpio_data = internal_peripheral::IpGPIO::load(db_dir, &gpio) + .map_err(|e| format!("Could not load IP GPIO file: {}", e))?; + render_pin_modes(&gpio_data); + println!("\n"); + } + Ok(()) +} + +/// Generate code containing the EEPROM size. +fn generate_eeprom_sizes(mcu_eeprom_size_map: &HashMap>) -> Result<(), String> { + println!("// EEPROM sizes in bytes, generated with cube-parse"); + for size in mcu_eeprom_size_map.keys() { + println!("#[cfg(feature = \"{}\")]", eeprom_size_to_feature(*size)); + println!("const EEPROM_SIZE_BYTES: u32 = {};", size); + } + Ok(()) +} + fn render_pin_modes(ip: &internal_peripheral::IpGPIO) { let mut pin_map: HashMap> = HashMap::new(); @@ -46,39 +416,29 @@ fn render_pin_modes(ip: &internal_peripheral::IpGPIO) { println!("}}"); } -fn main() { - let args: Vec = env::args().collect(); - if args.len() != 3 { - eprintln!("Usage: ./cube-parse CUBEMX_MCU_DB_DIR MCU_FAMILY") - } - - let db_dir = Path::new(&args[1]); +#[cfg(test)] +mod tests { + use super::*; - let familys = family::Families::load(&db_dir).unwrap(); + #[test] + fn test_gpio_version_to_feature() { + // Success + assert_eq!( + gpio_version_to_feature("STM32L152x8_gpio_v1_0").unwrap(), + "io-STM32L152x8" + ); + assert_eq!( + gpio_version_to_feature("STM32F333_gpio_v1_0").unwrap(), + "io-STM32F333" + ); - let family = (&familys).into_iter().find(|v| v.name == args[2]).unwrap(); + // Error parsing, unsupported version + assert!(gpio_version_to_feature("STM32F333_gpio_v1_1").is_err()); - let mut mcu_gpio_map = HashMap::new(); + // Error parsing, wrong pattern + assert!(gpio_version_to_feature("STM32F333_qqio_v1_0").is_err()); - for sf in family { - for mcu in sf { - let mcu_dat = mcu::Mcu::load(&db_dir, &mcu.name).unwrap(); - let gpio_version = mcu_dat.get_ip("GPIO").unwrap().get_version().to_string(); - if !mcu_gpio_map.contains_key(&gpio_version) { - mcu_gpio_map.insert(gpio_version.clone(), Vec::new()); - } - mcu_gpio_map.get_mut(&gpio_version).unwrap().push(mcu.name.clone()); - } - } - - for (gpio, mcu_list) in mcu_gpio_map { - let gpio_data = internal_peripheral::IpGPIO::load(db_dir, &gpio).unwrap(); - println!("#[cfg(any("); - for mcu in mcu_list { - println!(" feature = {:?},", mcu); - } - println!("))]"); - render_pin_modes(&gpio_data); - println!("\n"); + // Error parsing, too many underscores + assert!(gpio_version_to_feature("STM32_STM32F333_gpio_v1_0").is_err()); } } diff --git a/src/mcu.rs b/src/mcu.rs index 9d8977f..53533db 100644 --- a/src/mcu.rs +++ b/src/mcu.rs @@ -1,6 +1,6 @@ +use std::error::Error; use std::path::Path; -use serde; use serde_derive::Deserialize; use crate::utils::load_file; @@ -9,17 +9,23 @@ use crate::utils::load_file; pub struct Mcu { #[serde(rename = "IP", default)] ip: Vec, + #[serde(rename = "E2prom")] + eeprom_size_bytes: String, } impl Mcu { - pub fn load>(db_dir: P, mcu_name: &str) -> Result> { + pub fn load>(db_dir: P, mcu_name: &str) -> Result> { load_file(db_dir, format!("{}.xml", mcu_name)) } - pub fn get_ip(&self, name: &str) -> Option<&IP> { self.ip.iter().find(|v| v.name == name) } + + /// Return the EEPROM size in bytes + pub fn get_eeprom_size(&self) -> Option { + self.eeprom_size_bytes.parse().ok() + } } #[derive(Debug, Deserialize)] diff --git a/src/utils.rs b/src/utils.rs index 0d7f7b8..1da2d16 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -1,15 +1,13 @@ -use std::{ - error::Error, - io::BufReader, - fs::File, - path::Path, -}; +use std::{error::Error, fs::File, io::BufReader, path::Path}; use serde::Deserialize; -pub fn load_file<'a, P: AsRef, Q: AsRef, R: Deserialize<'a>>(db_dir: P, file_path: Q) -> Result> { +pub fn load_file<'a, P: AsRef, Q: AsRef, R: Deserialize<'a>>( + db_dir: P, + file_path: Q, +) -> Result> { let db_dir = db_dir.as_ref(); let mut fin = BufReader::new(File::open(&db_dir.join(file_path.as_ref()))?); Ok(serde_xml_rs::deserialize(&mut fin)?) -} \ No newline at end of file +}