diff --git a/.gitignore b/.gitignore index caa84fe..ea8c4bf 100644 --- a/.gitignore +++ b/.gitignore @@ -1,64 +1 @@ -.lck -*.class -/components/basys.components/WebContent/WEB-INF/lib/jdbc/postgresql-42.2.2.jar -/components/basys.components/WebContent/WEB-INF/lib/jersey/ext/aopalliance-repackaged-2.5.0-b42.jar -/components/basys.components/WebContent/WEB-INF/lib/jersey/ext/cdi-api-1.1.jar -/components/basys.components/WebContent/WEB-INF/lib/jersey/ext/el-api-2.2.jar -/components/basys.components/WebContent/WEB-INF/lib/jersey/ext/hk2-api-2.5.0-b42.jar -/components/basys.components/WebContent/WEB-INF/lib/jersey/ext/hk2-locator-2.5.0-b42.jar -/components/basys.components/WebContent/WEB-INF/lib/jersey/ext/hk2-utils-2.5.0-b42.jar -/components/basys.components/WebContent/WEB-INF/lib/jersey/ext/javassist-3.22.0-CR2.jar -/components/basys.components/WebContent/WEB-INF/lib/jersey/ext/javax.annotation-api-1.2.jar -/components/basys.components/WebContent/WEB-INF/lib/jersey/ext/javax.inject-1.jar -/components/basys.components/WebContent/WEB-INF/lib/jersey/ext/javax.inject-2.5.0-b42.jar -/components/basys.components/WebContent/WEB-INF/lib/jersey/ext/javax.json-1.1.jar -/components/basys.components/WebContent/WEB-INF/lib/jersey/ext/javax.json-api-1.1.jar -/components/basys.components/WebContent/WEB-INF/lib/jersey/ext/javax.json.bind-api-1.0.jar -/components/basys.components/WebContent/WEB-INF/lib/jersey/ext/javax.servlet-api-3.0.1.jar -/components/basys.components/WebContent/WEB-INF/lib/jersey/ext/jaxb-api-2.2.7.jar -/components/basys.components/WebContent/WEB-INF/lib/jersey/ext/jboss-interceptors-api_1.1_spec-1.0.0.Beta1.jar -/components/basys.components/WebContent/WEB-INF/lib/jersey/ext/jsr250-api-1.0.jar -/components/basys.components/WebContent/WEB-INF/lib/jersey/ext/org.osgi.core-4.2.0.jar -/components/basys.components/WebContent/WEB-INF/lib/jersey/ext/osgi-resource-locator-1.0.1.jar -/components/basys.components/WebContent/WEB-INF/lib/jersey/ext/persistence-api-1.0.jar -/components/basys.components/WebContent/WEB-INF/lib/jersey/ext/validation-api-1.1.0.Final.jar -/components/basys.components/WebContent/WEB-INF/lib/jersey/ext/yasson-1.0.jar -/components/basys.components/WebContent/WEB-INF/lib/jersey/javax.ws.rs-api-2.1.jar -/components/basys.components/WebContent/WEB-INF/lib/jersey/jersey-client.jar -/components/basys.components/WebContent/WEB-INF/lib/jersey/jersey-common.jar -/components/basys.components/WebContent/WEB-INF/lib/jersey/jersey-container-servlet-core.jar -/components/basys.components/WebContent/WEB-INF/lib/jersey/jersey-container-servlet.jar -/components/basys.components/WebContent/WEB-INF/lib/jersey/jersey-hk2.jar -/components/basys.components/WebContent/WEB-INF/lib/jersey/jersey-media-jaxb.jar -/components/basys.components/WebContent/WEB-INF/lib/jersey/jersey-media-json-binding.jar -/components/basys.components/WebContent/WEB-INF/lib/jersey/jersey-media-sse.jar -/components/basys.components/WebContent/WEB-INF/lib/jersey/jersey-server.jar -/components/basys.components/WebContent/WEB-INF/lib/poi-4.0.0/LICENSE -/components/basys.components/WebContent/WEB-INF/lib/poi-4.0.0/NOTICE -/components/basys.components/WebContent/WEB-INF/lib/poi-4.0.0/lib/activation-1.1.1.jar -/components/basys.components/WebContent/WEB-INF/lib/poi-4.0.0/lib/commons-codec-1.11.jar -/components/basys.components/WebContent/WEB-INF/lib/poi-4.0.0/lib/commons-collections4-4.2.jar -/components/basys.components/WebContent/WEB-INF/lib/poi-4.0.0/lib/commons-logging-1.2.jar -/components/basys.components/WebContent/WEB-INF/lib/poi-4.0.0/lib/commons-math3-3.6.1.jar -/components/basys.components/WebContent/WEB-INF/lib/poi-4.0.0/lib/jaxb-api-2.3.0.jar -/components/basys.components/WebContent/WEB-INF/lib/poi-4.0.0/lib/jaxb-core-2.3.0.1.jar -/components/basys.components/WebContent/WEB-INF/lib/poi-4.0.0/lib/jaxb-impl-2.3.0.1.jar -/components/basys.components/WebContent/WEB-INF/lib/poi-4.0.0/lib/junit-4.12.jar -/components/basys.components/WebContent/WEB-INF/lib/poi-4.0.0/lib/log4j-1.2.17.jar -/components/basys.components/WebContent/WEB-INF/lib/poi-4.0.0/ooxml-lib/curvesapi-1.05.jar -/components/basys.components/WebContent/WEB-INF/lib/poi-4.0.0/ooxml-lib/xmlbeans-3.0.1.jar -/components/basys.components/WebContent/WEB-INF/lib/poi-4.0.0/poi-4.0.0.jar -/components/basys.components/WebContent/WEB-INF/lib/poi-4.0.0/poi-examples-4.0.0.jar -/components/basys.components/WebContent/WEB-INF/lib/poi-4.0.0/poi-excelant-4.0.0.jar -/components/basys.components/WebContent/WEB-INF/lib/poi-4.0.0/poi-ooxml-4.0.0.jar -/components/basys.components/WebContent/WEB-INF/lib/poi-4.0.0/poi-ooxml-schemas-4.0.0.jar -/components/basys.components/WebContent/WEB-INF/lib/poi-4.0.0/poi-scratchpad-4.0.0.jar -/components/basys.components/WebContent/WEB-INF/lib/saxonxmlparser/saxon9-xqj.jar -/components/basys.components/WebContent/WEB-INF/lib/saxonxmlparser/saxon9he.jar -/components/basys.components/WebContent/WEB-INF/lib/sdk/basyx_sdk.jar -/.vs -/sdks/dotnet/.vs/BaSyx -launchSettings.json -.project -*.pubxml -Properties +/target diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 0000000..6517a35 --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,799 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "addr2line" +version = "0.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9ecd88a8c8378ca913a680cd98f0f13ac67383d35993f86c90a70e3f137816b" +dependencies = [ + "gimli", +] + +[[package]] +name = "adler" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" + +[[package]] +name = "aho-corasick" +version = "0.7.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e37cfd5e7657ada45f742d6e99ca5788580b5c529dc78faf11ece6dc702656f" +dependencies = [ + "memchr", +] + +[[package]] +name = "atty" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" +dependencies = [ + "hermit-abi", + "libc", + "winapi", +] + +[[package]] +name = "autocfg" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a" + +[[package]] +name = "backtrace" +version = "0.3.63" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "321629d8ba6513061f26707241fa9bc89524ff1cd7a915a97ef0c62c666ce1b6" +dependencies = [ + "addr2line", + "cc", + "cfg-if", + "libc", + "miniz_oxide", + "object", + "rustc-demangle", +] + +[[package]] +name = "base64" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "904dfeac50f3cdaba28fc6f57fdcddb75f49ed61346676a78c4ffe55877802fd" + +[[package]] +name = "basyx-rs" +version = "0.1.0" +dependencies = [ + "clap", + "color-eyre", + "colored", + "jsonschema", + "serde", + "serde_json", + "thiserror", +] + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "cc" +version = "1.0.71" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "79c2681d6594606957bbb8631c4b90a7fcaaa72cdb714743a437b156d6a7eedd" + +[[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.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "670ad68c9088c2a963aaa298cb369688cf3f9465ce5e2d4ca10e6e0098a1ce73" +dependencies = [ + "libc", + "num-integer", + "num-traits", + "time", + "winapi", +] + +[[package]] +name = "clap" +version = "3.0.0-beta.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "feff3878564edb93745d58cf63e17b63f24142506e7a20c87a5521ed7bfb1d63" +dependencies = [ + "atty", + "bitflags", + "clap_derive", + "indexmap", + "lazy_static", + "os_str_bytes", + "strsim", + "termcolor", + "textwrap", + "unicase", +] + +[[package]] +name = "clap_derive" +version = "3.0.0-beta.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b15c6b4f786ffb6192ffe65a36855bc1fc2444bcd0945ae16748dcd6ed7d0d3" +dependencies = [ + "heck", + "proc-macro-error", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "color-eyre" +version = "0.5.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f1885697ee8a177096d42f158922251a41973117f6d8a234cee94b9509157b7" +dependencies = [ + "backtrace", + "eyre", + "indenter", + "once_cell", + "owo-colors", +] + +[[package]] +name = "colored" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b3616f750b84d8f0de8a58bda93e08e2a81ad3f523089b05f1dffecab48c6cbd" +dependencies = [ + "atty", + "lazy_static", + "winapi", +] + +[[package]] +name = "crossbeam-channel" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06ed27e177f16d65f0f0c22a213e17c696ace5dd64b14258b52f9417ccb52db4" +dependencies = [ + "cfg-if", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-deque" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6455c0ca19f0d2fbf751b908d5c55c1f5cbc65e03c4225427254b46890bdde1e" +dependencies = [ + "cfg-if", + "crossbeam-epoch", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-epoch" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ec02e091aa634e2c3ada4a392989e7c3116673ef0ac5b72232439094d73b7fd" +dependencies = [ + "cfg-if", + "crossbeam-utils", + "lazy_static", + "memoffset", + "scopeguard", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d82cfc11ce7f2c3faef78d8a684447b40d503d9681acebed6cb728d45940c4db" +dependencies = [ + "cfg-if", + "lazy_static", +] + +[[package]] +name = "either" +version = "1.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457" + +[[package]] +name = "eyre" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "221239d1d5ea86bf5d6f91c9d6bc3646ffe471b08ff9b0f91c44f115ac969d2b" +dependencies = [ + "indenter", + "once_cell", +] + +[[package]] +name = "form_urlencoded" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5fc25a87fa4fd2094bffb06925852034d90a17f0d1e05197d4956d3555752191" +dependencies = [ + "matches", + "percent-encoding", +] + +[[package]] +name = "gimli" +version = "0.26.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78cc372d058dcf6d5ecd98510e7fbc9e5aec4d21de70f65fea8fecebcd881bd4" + +[[package]] +name = "hashbrown" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e" + +[[package]] +name = "heck" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d621efb26863f0e9924c6ac577e8275e5e6b77455db64ffa6c65c904e9e132c" +dependencies = [ + "unicode-segmentation", +] + +[[package]] +name = "hermit-abi" +version = "0.1.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" +dependencies = [ + "libc", +] + +[[package]] +name = "idna" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "418a0a6fab821475f634efe3ccc45c013f742efe03d853e8d3355d5cb850ecf8" +dependencies = [ + "matches", + "unicode-bidi", + "unicode-normalization", +] + +[[package]] +name = "indenter" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce23b50ad8242c51a442f3ff322d56b02f08852c77e4c0b4d3fd684abc89c683" + +[[package]] +name = "indexmap" +version = "1.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc633605454125dec4b66843673f01c7df2b89479b32e0ed634e43a91cff62a5" +dependencies = [ + "autocfg", + "hashbrown", +] + +[[package]] +name = "instant" +version = "0.1.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "itoa" +version = "0.4.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b71991ff56294aa922b450139ee08b3bfc70982c6b2c7562771375cf73542dd4" + +[[package]] +name = "jsonschema" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6eee5c16f8d96dcb43b6458faeed3d1556a7cbea7c72fd5d1e481484605e2bf" +dependencies = [ + "base64", + "chrono", + "idna", + "lazy_static", + "num-cmp", + "parking_lot", + "percent-encoding", + "rayon", + "regex", + "serde_json", + "url", +] + +[[package]] +name = "lazy_static" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" + +[[package]] +name = "libc" +version = "0.2.106" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a60553f9a9e039a333b4e9b20573b9e9b9c0bb3a11e201ccc48ef4283456d673" + +[[package]] +name = "lock_api" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712a4d093c9976e24e7dbca41db895dabcbac38eb5f4045393d17a95bdfb1109" +dependencies = [ + "scopeguard", +] + +[[package]] +name = "matches" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a3e378b66a060d48947b590737b30a1be76706c8dd7b8ba0f2fe3989c68a853f" + +[[package]] +name = "memchr" +version = "2.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a" + +[[package]] +name = "memoffset" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59accc507f1338036a0477ef61afdae33cde60840f4dfe481319ce3ad116ddf9" +dependencies = [ + "autocfg", +] + +[[package]] +name = "miniz_oxide" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a92518e98c078586bc6c934028adcca4c92a53d6a958196de835170a01d84e4b" +dependencies = [ + "adler", + "autocfg", +] + +[[package]] +name = "num-cmp" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "63335b2e2c34fae2fb0aa2cecfd9f0832a1e24b3b32ecec612c3426d46dc8aaa" + +[[package]] +name = "num-integer" +version = "0.1.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2cc698a63b549a70bc047073d2949cce27cd1c7b0a4a862d08a8031bc2801db" +dependencies = [ + "autocfg", + "num-traits", +] + +[[package]] +name = "num-traits" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a64b1ec5cda2586e284722486d802acf1f7dbdc623e2bfc57e65ca1cd099290" +dependencies = [ + "autocfg", +] + +[[package]] +name = "num_cpus" +version = "1.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05499f3756671c15885fee9034446956fff3f243d6077b91e5767df161f766b3" +dependencies = [ + "hermit-abi", + "libc", +] + +[[package]] +name = "object" +version = "0.27.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67ac1d3f9a1d3616fd9a60c8d74296f22406a238b6a72f5cc1e6f314df4ffbf9" +dependencies = [ + "memchr", +] + +[[package]] +name = "once_cell" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "692fcb63b64b1758029e0a96ee63e049ce8c5948587f2f7208df04625e5f6b56" + +[[package]] +name = "os_str_bytes" +version = "4.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "addaa943333a514159c80c97ff4a93306530d965d27e139188283cd13e06a799" +dependencies = [ + "memchr", +] + +[[package]] +name = "owo-colors" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2386b4ebe91c2f7f51082d4cefa145d030e33a1842a96b12e4885cc3c01f7a55" + +[[package]] +name = "parking_lot" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d17b78036a60663b797adeaee46f5c9dfebb86948d1255007a1d6be0271ff99" +dependencies = [ + "instant", + "lock_api", + "parking_lot_core", +] + +[[package]] +name = "parking_lot_core" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d76e8e1493bcac0d2766c42737f34458f1c8c50c0d23bcb24ea953affb273216" +dependencies = [ + "cfg-if", + "instant", + "libc", + "redox_syscall", + "smallvec", + "winapi", +] + +[[package]] +name = "percent-encoding" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4fd5641d01c8f18a23da7b6fe29298ff4b55afcccdf78973b24cf3175fee32e" + +[[package]] +name = "proc-macro-error" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" +dependencies = [ + "proc-macro-error-attr", + "proc-macro2", + "quote", + "syn", + "version_check", +] + +[[package]] +name = "proc-macro-error-attr" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" +dependencies = [ + "proc-macro2", + "quote", + "version_check", +] + +[[package]] +name = "proc-macro2" +version = "1.0.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba508cc11742c0dc5c1659771673afbab7a0efab23aa17e854cbab0837ed0b43" +dependencies = [ + "unicode-xid", +] + +[[package]] +name = "quote" +version = "1.0.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38bc8cc6a5f2e3655e0899c1b848643b2562f853f114bfec7be120678e3ace05" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "rayon" +version = "1.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c06aca804d41dbc8ba42dfd964f0d01334eceb64314b9ecf7c5fad5188a06d90" +dependencies = [ + "autocfg", + "crossbeam-deque", + "either", + "rayon-core", +] + +[[package]] +name = "rayon-core" +version = "1.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d78120e2c850279833f1dd3582f730c4ab53ed95aeaaaa862a2a5c71b1656d8e" +dependencies = [ + "crossbeam-channel", + "crossbeam-deque", + "crossbeam-utils", + "lazy_static", + "num_cpus", +] + +[[package]] +name = "redox_syscall" +version = "0.2.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8383f39639269cde97d255a32bdb68c047337295414940c68bdd30c2e13203ff" +dependencies = [ + "bitflags", +] + +[[package]] +name = "regex" +version = "1.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d07a8629359eb56f1e2fb1652bb04212c072a87ba68546a04065d525673ac461" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.6.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f497285884f3fcff424ffc933e56d7cbca511def0c9831a7f9b5f6153e3cc89b" + +[[package]] +name = "rustc-demangle" +version = "0.1.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ef03e0a2b150c7a90d01faf6254c9c48a41e95fb2a8c2ac1c6f0d2b9aefc342" + +[[package]] +name = "ryu" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "71d301d4193d031abdd79ff7e3dd721168a9572ef3fe51a1517aba235bd8f86e" + +[[package]] +name = "scopeguard" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" + +[[package]] +name = "serde" +version = "1.0.130" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f12d06de37cf59146fbdecab66aa99f9fe4f78722e3607577a5375d66bd0c913" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.130" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7bc1a1ab1961464eae040d96713baa5a724a8152c1222492465b54322ec508b" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "serde_json" +version = "1.0.68" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f690853975602e1bfe1ccbf50504d67174e3bcf340f23b5ea9992e0587a52d8" +dependencies = [ + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "smallvec" +version = "1.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ecab6c735a6bb4139c0caafd0cc3635748bbb3acf4550e8138122099251f309" + +[[package]] +name = "strsim" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" + +[[package]] +name = "syn" +version = "1.0.81" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2afee18b8beb5a596ecb4a2dce128c719b4ba399d34126b9e4396e3f9860966" +dependencies = [ + "proc-macro2", + "quote", + "unicode-xid", +] + +[[package]] +name = "termcolor" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2dfed899f0eb03f32ee8c6a0aabdb8a7949659e3466561fc0adf54e26d88c5f4" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "textwrap" +version = "0.14.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0066c8d12af8b5acd21e00547c3797fde4e8677254a7ee429176ccebbe93dd80" +dependencies = [ + "unicode-width", +] + +[[package]] +name = "thiserror" +version = "1.0.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "854babe52e4df1653706b98fcfc05843010039b406875930a70e4d9644e5c417" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa32fd3f627f367fe16f893e2597ae3c05020f8bba2666a4e6ea73d377e5714b" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "time" +version = "0.1.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6db9e6914ab8b1ae1c260a4ae7a49b6c5611b40328a735b21862567685e73255" +dependencies = [ + "libc", + "wasi", + "winapi", +] + +[[package]] +name = "tinyvec" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f83b2a3d4d9091d0abd7eba4dc2710b1718583bd4d8992e2190720ea38f391f7" +dependencies = [ + "tinyvec_macros", +] + +[[package]] +name = "tinyvec_macros" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c" + +[[package]] +name = "unicase" +version = "2.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50f37be617794602aabbeee0be4f259dc1778fabe05e2d67ee8f79326d5cb4f6" +dependencies = [ + "version_check", +] + +[[package]] +name = "unicode-bidi" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a01404663e3db436ed2746d9fefef640d868edae3cceb81c3b8d5732fda678f" + +[[package]] +name = "unicode-normalization" +version = "0.1.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d54590932941a9e9266f0832deed84ebe1bf2e4c9e4a3554d393d18f5e854bf9" +dependencies = [ + "tinyvec", +] + +[[package]] +name = "unicode-segmentation" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8895849a949e7845e06bd6dc1aa51731a103c42707010a5b591c0038fb73385b" + +[[package]] +name = "unicode-width" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ed742d4ea2bd1176e236172c8429aaf54486e7ac098db29ffe6529e0ce50973" + +[[package]] +name = "unicode-xid" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3" + +[[package]] +name = "url" +version = "2.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a507c383b2d33b5fc35d1861e77e6b383d158b2da5e14fe51b83dfedf6fd578c" +dependencies = [ + "form_urlencoded", + "idna", + "matches", + "percent-encoding", +] + +[[package]] +name = "version_check" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5fecdca9a5291cc2b8dcf7dc02453fee791a280f3743cb0905f8822ae463b3fe" + +[[package]] +name = "wasi" +version = "0.10.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a143597ca7c7793eff794def352d41792a93c481eb1042423ff7ff72ba2c31f" + +[[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-util" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" +dependencies = [ + "winapi", +] + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..8eaedaf --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,29 @@ +[package] +name = "basyx-rs" +authors = ["Daniel Hillen ", "Andreas Schmidt "] +description = "A Rust library to work with Asset Administration Shells." +documentation = "https://github.com/eclipse-basyx/rust-sdk/blob/main/README.md" +keywords = ["aas", "basyx", "serde"] +license = "EPL-2.0" +repository = "https://github.com/eclipse-basyx/rust-sdk" +version = "0.1.0" +edition = "2018" + +[[bin]] +name = "aascheck" +path = "src/bin/aascheck.rs" +test = false +bench = false + +[dependencies] +clap = { version = "=3.0.0-beta.5", optional = true } +color-eyre = { version = "0.5.6", default-features = false } +colored = "2.0.0" +jsonschema = { version = "0.5.0", default-features = false } +serde = { version = "1.0", features = ["derive"] } +serde_json = "1.0" +thiserror = "1.0.20" + +[features] +default = ["clap"] +explorer = [] \ No newline at end of file diff --git a/README b/README deleted file mode 100644 index a81d54f..0000000 --- a/README +++ /dev/null @@ -1,6 +0,0 @@ -The Eclipse BaSyx project provides a wiki: https://wiki.eclipse.org/BaSyx - -For install information, see https://wiki.eclipse.org/BaSyx_/_Download -There are introductory examples provided by https://wiki.eclipse.org/BaSyx_/_Introductory_Examples -Additionally, the API is described in https://wiki.eclipse.org/BaSyx_/_Documentation_/_API -If you would like to contribute, the overall process is described in https://wiki.eclipse.org/BaSyx_/_Developer_/_Contributing \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..9d34b90 --- /dev/null +++ b/README.md @@ -0,0 +1,24 @@ +# BaSyx Rust SDK + +A Rust library to work with Asset Administration Shells (AAS). + +The Eclipse BaSyx project provides a [wiki](https://wiki.eclipse.org/BaSyx). + +For install information, see [this page](https://wiki.eclipse.org/BaSyx_/_Download). +There are introductory examples provided [here](https://wiki.eclipse.org/BaSyx_/_Introductory_Examples). +Additionally, the API is described [here](https://wiki.eclipse.org/BaSyx_/_Documentation_/_API). +If you would like to contribute, the overall process is described [here](https://wiki.eclipse.org/BaSyx_/_Developer_/_Contributing). + +## Checking JSON Files + +Installing this crate with `cargo install --path .` provides access to the `aascheck` binary utility: + +```bash +aascheck --mode Submodel +``` + +or for a complete AAS environment: + +```bash +aascheck --mode AAS +``` diff --git a/about.hbs b/about.hbs new file mode 100644 index 0000000..699b3b0 --- /dev/null +++ b/about.hbs @@ -0,0 +1,70 @@ + + + + + + + +
+
+

Third Party Licenses

+

This page lists the licenses of the projects used in cargo-about.

+
+ +

Overview of licenses:

+
    + {{#each overview}} +
  • {{name}} ({{count}})
  • + {{/each}} +
+ +

All license text:

+ +
+ + + diff --git a/about.toml b/about.toml new file mode 100644 index 0000000..60600fe --- /dev/null +++ b/about.toml @@ -0,0 +1,7 @@ +accepted = [ + "Apache-2.0", + "BSD-3-Clause", + "EPL-2.0", + "MIT", + "MPL-2.0" +] diff --git a/examples/generate.rs b/examples/generate.rs new file mode 100644 index 0000000..1a9342f --- /dev/null +++ b/examples/generate.rs @@ -0,0 +1,32 @@ +use basyx_rs::prelude::*; +use color_eyre::eyre::Result; +use std::io::Write; + +fn main() -> Result<()> { + let mut property = Property::new( + "property".into(), + Some(Value::Boolean(false)), + DataObjectTypeName::Boolean, + ); + property.category = Some(Category::CONSTANT); + property.kind = Some(ModelingKind::Instance); + + let sme = SubmodelElement::SMProperty(property); + + let sm = Submodel::new("submodel1".into(), KeyType::IdShort, "i".into(), vec![sme]); + serialize("submodel1.json", &sm) +} + +fn serialize(path: &str, submodel: &Submodel) -> Result<()> { + let json = serde_json::to_vec(submodel)?; + let mut file = std::fs::OpenOptions::new() + .create(true) + .write(true) + .read(true) + .truncate(true) + .open(path)?; + file.write_all(&json)?; + + println!("Generated: {}", path); + Ok(()) +} diff --git a/schema/aas.json b/schema/aas.json new file mode 100644 index 0000000..48428f6 --- /dev/null +++ b/schema/aas.json @@ -0,0 +1,1546 @@ +{ + "$schema": "https://json-schema.org/draft/2019-09/schema", + "title": "AssetAdministrationShellEnvironment", + "$id": "http://www.admin-shell.io/schema/json/V3.0RC01", + "type": "object", + "required": [ + "assetAdministrationShells", + "submodels", + "assets", + "conceptDescriptions" + ], + "properties": { + "assetAdministrationShells": { + "type": "array", + "items": { + "$ref": "#/definitions/AssetAdministrationShell" + } + }, + "submodels": { + "type": "array", + "items": { + "$ref": "#/definitions/Submodel" + } + }, + "assets": { + "type": "array", + "items": { + "$ref": "#/definitions/Asset" + } + }, + "conceptDescriptions": { + "type": "array", + "items": { + "$ref": "#/definitions/ConceptDescription" + } + } + }, + "definitions": { + "Referable": { + "allOf": [ + { + "$ref": "#/definitions/HasExtensions" + }, + { + "properties": { + "idShort": { + "type": "string" + }, + "category": { + "type": "string" + }, + "displayName": { + "type": "string" + }, + "description": { + "type": "array", + "items": { + "$ref": "#/definitions/LangString" + } + }, + "modelType": { + "$ref": "#/definitions/ModelType" + } + }, + "required": [ + "modelType", + "idShort" + ] + } + ] + }, + "Identifiable": { + "allOf": [ + { + "$ref": "#/definitions/Referable" + }, + { + "properties": { + "identification": { + "$ref": "#/definitions/Identifier" + }, + "administration": { + "$ref": "#/definitions/AdministrativeInformation" + } + }, + "required": [ + "identification" + ] + } + ] + }, + "Qualifiable": { + "type": "object", + "properties": { + "qualifiers": { + "type": "array", + "items": { + "$ref": "#/definitions/Constraint" + } + } + } + }, + "HasSemantics": { + "type": "object", + "properties": { + "semanticId": { + "$ref": "#/definitions/Reference" + } + } + }, + "HasDataSpecification": { + "type": "object", + "properties": { + "embeddedDataSpecifications": { + "type": "array", + "items": { + "$ref": "#/definitions/EmbeddedDataSpecification" + } + } + } + }, + "HasExtensions": { + "type": "object", + "properties": { + "extensions": { + "type": "array", + "items": { + "$ref": "#/definitions/Extension" + } + } + } + }, + "Extension": { + "allOf": [ + { + "$ref": "#/definitions/HasSemantics" + }, + { + "properties": { + "name": { + "type": "string" + }, + "valueType": { + "type": "string", + "enum": [ + "anyUri", + "base64Binary", + "boolean", + "date", + "dateTime", + "dateTimeStamp", + "decimal", + "integer", + "long", + "int", + "short", + "byte", + "nonNegativeInteger", + "positiveInteger", + "unsignedLong", + "unsignedInt", + "unsignedShort", + "unsignedByte", + "nonPositiveInteger", + "negativeInteger", + "double", + "duration", + "dayTimeDuration", + "yearMonthDuration", + "float", + "gDay", + "gMonth", + "gMonthDay", + "gYear", + "gYearMonth", + "hexBinary", + "NOTATION", + "QName", + "string", + "normalizedString", + "token", + "language", + "Name", + "NCName", + "ENTITY", + "ID", + "IDREF", + "NMTOKEN", + "time" + ] + }, + "value": { + "type": "string" + }, + "refersTo": { + "$ref": "#/definitions/Reference" + } + }, + "required": [ + "name" + ] + } + ] + }, + "AssetAdministrationShell": { + "allOf": [ + { + "$ref": "#/definitions/Identifiable" + }, + { + "$ref": "#/definitions/HasDataSpecification" + }, + { + "properties": { + "derivedFrom": { + "$ref": "#/definitions/Reference" + }, + "assetInformation": { + "$ref": "#/definitions/AssetInformation" + }, + "submodels": { + "type": "array", + "items": { + "$ref": "#/definitions/Reference" + } + }, + "views": { + "type": "array", + "items": { + "$ref": "#/definitions/View" + } + }, + "security": { + "$ref": "#/definitions/Security" + } + }, + "required": [ + "assetInformation" + ] + } + ] + }, + "Identifier": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "idType": { + "$ref": "#/definitions/KeyType" + } + }, + "required": [ + "id", + "idType" + ] + }, + "KeyType": { + "type": "string", + "enum": [ + "Custom", + "IRDI", + "IRI", + "IdShort", + "FragmentId" + ] + }, + "AdministrativeInformation": { + "type": "object", + "properties": { + "version": { + "type": "string" + }, + "revision": { + "type": "string" + } + } + }, + "LangString": { + "type": "object", + "properties": { + "language": { + "type": "string" + }, + "text": { + "type": "string" + } + }, + "required": [ + "language", + "text" + ] + }, + "Reference": { + "type": "object", + "properties": { + "keys": { + "type": "array", + "items": { + "$ref": "#/definitions/Key" + } + } + }, + "required": [ + "keys" + ] + }, + "Key": { + "type": "object", + "properties": { + "type": { + "$ref": "#/definitions/KeyElements" + }, + "idType": { + "$ref": "#/definitions/KeyType" + }, + "value": { + "type": "string" + } + }, + "required": [ + "type", + "idType", + "value" + ] + }, + "KeyElements": { + "type": "string", + "enum": [ + "Asset", + "AssetAdministrationShell", + "ConceptDescription", + "Submodel", + "AccessPermissionRule", + "AnnotatedRelationshipElement", + "BasicEvent", + "Blob", + "Capability", + "DataElement", + "File", + "Entity", + "Event", + "MultiLanguageProperty", + "Operation", + "Property", + "Range", + "ReferenceElement", + "RelationshipElement", + "SubmodelElement", + "SubmodelElementCollection", + "View", + "GlobalReference", + "FragmentReference" + ] + }, + "ModelTypes": { + "type": "string", + "enum": [ + "Asset", + "AssetAdministrationShell", + "ConceptDescription", + "Submodel", + "AccessPermissionRule", + "AnnotatedRelationshipElement", + "BasicEvent", + "Blob", + "Capability", + "DataElement", + "File", + "Entity", + "Event", + "MultiLanguageProperty", + "Operation", + "Property", + "Range", + "ReferenceElement", + "RelationshipElement", + "SubmodelElement", + "SubmodelElementCollection", + "View", + "GlobalReference", + "FragmentReference", + "Constraint", + "Formula", + "Qualifier" + ] + }, + "ModelType": { + "type": "object", + "properties": { + "name": { + "$ref": "#/definitions/ModelTypes" + } + }, + "required": [ + "name" + ] + }, + "EmbeddedDataSpecification": { + "type": "object", + "properties": { + "dataSpecification": { + "$ref": "#/definitions/Reference" + }, + "dataSpecificationContent": { + "$ref": "#/definitions/DataSpecificationContent" + } + }, + "required": [ + "dataSpecification", + "dataSpecificationContent" + ] + }, + "DataSpecificationContent": { + "oneOf": [ + { + "$ref": "#/definitions/DataSpecificationIEC61360Content" + }, + { + "$ref": "#/definitions/DataSpecificationPhysicalUnitContent" + } + ] + }, + "DataSpecificationPhysicalUnitContent": { + "type": "object", + "properties": { + "unitName": { + "type": "string" + }, + "unitSymbol": { + "type": "string" + }, + "definition": { + "type": "array", + "items": { + "$ref": "#/definitions/LangString" + } + }, + "siNotation": { + "type": "string" + }, + "siName": { + "type": "string" + }, + "dinNotation": { + "type": "string" + }, + "eceName": { + "type": "string" + }, + "eceCode": { + "type": "string" + }, + "nistName": { + "type": "string" + }, + "sourceOfDefinition": { + "type": "string" + }, + "conversionFactor": { + "type": "string" + }, + "registrationAuthorityId": { + "type": "string" + }, + "supplier": { + "type": "string" + } + }, + "required": [ + "unitName", + "unitSymbol", + "definition" + ] + }, + "DataSpecificationIEC61360Content": { + "allOf": [ + { + "$ref": "#/definitions/ValueObject" + }, + { + "type": "object", + "properties": { + "dataType": { + "enum": [ + "DATE", + "STRING", + "STRING_TRANSLATABLE", + "REAL_MEASURE", + "REAL_COUNT", + "REAL_CURRENCY", + "BOOLEAN", + "URL", + "RATIONAL", + "RATIONAL_MEASURE", + "TIME", + "TIMESTAMP", + "INTEGER_COUNT", + "INTEGER_MEASURE", + "INTEGER_CURRENCY" + ] + }, + "definition": { + "type": "array", + "items": { + "$ref": "#/definitions/LangString" + } + }, + "preferredName": { + "type": "array", + "items": { + "$ref": "#/definitions/LangString" + } + }, + "shortName": { + "type": "array", + "items": { + "$ref": "#/definitions/LangString" + } + }, + "sourceOfDefinition": { + "type": "string" + }, + "symbol": { + "type": "string" + }, + "unit": { + "type": "string" + }, + "unitId": { + "$ref": "#/definitions/Reference" + }, + "valueFormat": { + "type": "string" + }, + "valueList": { + "$ref": "#/definitions/ValueList" + }, + "levelType": { + "type": "array", + "items": { + "$ref": "#/definitions/LevelType" + } + } + }, + "required": [ + "preferredName" + ] + } + ] + }, + "LevelType": { + "type": "string", + "enum": [ + "Min", + "Max", + "Nom", + "Typ" + ] + }, + "ValueList": { + "type": "object", + "properties": { + "valueReferencePairTypes": { + "type": "array", + "minItems": 1, + "items": { + "$ref": "#/definitions/ValueReferencePairType" + } + } + }, + "required": [ + "valueReferencePairTypes" + ] + }, + "ValueReferencePairType": { + "allOf": [ + { + "$ref": "#/definitions/ValueObject" + } + ] + }, + "ValueObject": { + "type": "object", + "properties": { + "value": { + "type": "string" + }, + "valueId": { + "$ref": "#/definitions/Reference" + }, + "valueType": { + "type": "string", + "enum": [ + "anyUri", + "base64Binary", + "boolean", + "date", + "dateTime", + "dateTimeStamp", + "decimal", + "integer", + "long", + "int", + "short", + "byte", + "nonNegativeInteger", + "positiveInteger", + "unsignedLong", + "unsignedInt", + "unsignedShort", + "unsignedByte", + "nonPositiveInteger", + "negativeInteger", + "double", + "duration", + "dayTimeDuration", + "yearMonthDuration", + "float", + "gDay", + "gMonth", + "gMonthDay", + "gYear", + "gYearMonth", + "hexBinary", + "NOTATION", + "QName", + "string", + "normalizedString", + "token", + "language", + "Name", + "NCName", + "ENTITY", + "ID", + "IDREF", + "NMTOKEN", + "time" + ] + } + } + }, + "Asset": { + "allOf": [ + { + "$ref": "#/definitions/Identifiable" + }, + { + "$ref": "#/definitions/HasDataSpecification" + } + ] + }, + "AssetInformation": { + "allOf": [ + { + "properties": { + "assetKind": { + "$ref": "#/definitions/AssetKind" + }, + "globalAssetId": { + "$ref": "#/definitions/Reference" + }, + "specificAssetIds": { + "type": "array", + "items": { + "$ref": "#/definitions/IdentifierKeyValuePair" + } + }, + "billOfMaterial": { + "type": "array", + "items": { + "$ref": "#/definitions/Reference" + } + }, + "thumbnail": { + "$ref": "#/definitions/File" + } + }, + "required": [ + "assetKind" + ] + } + ] + }, + "IdentifierKeyValuePair": { + "allOf": [ + { + "$ref": "#/definitions/HasSemantics" + }, + { + "properties": { + "key": { + "type": "string" + }, + "value": { + "type": "string" + }, + "subjectId": { + "$ref": "#/definitions/Reference" + } + }, + "required": [ + "key", + "value", + "subjectId" + ] + } + ] + }, + "AssetKind": { + "type": "string", + "enum": [ + "Type", + "Instance" + ] + }, + "ModelingKind": { + "type": "string", + "enum": [ + "Template", + "Instance" + ] + }, + "Submodel": { + "allOf": [ + { + "$ref": "#/definitions/Identifiable" + }, + { + "$ref": "#/definitions/HasDataSpecification" + }, + { + "$ref": "#/definitions/Qualifiable" + }, + { + "$ref": "#/definitions/HasSemantics" + }, + { + "properties": { + "kind": { + "$ref": "#/definitions/ModelingKind" + }, + "submodelElements": { + "type": "array", + "items": { + "$ref": "#/definitions/SubmodelElement" + } + } + } + } + ] + }, + "Constraint": { + "type": "object", + "properties": { + "modelType": { + "$ref": "#/definitions/ModelType" + } + }, + "required": [ + "modelType" + ] + }, + "Operation": { + "allOf": [ + { + "$ref": "#/definitions/SubmodelElement" + }, + { + "properties": { + "inputVariable": { + "type": "array", + "items": { + "$ref": "#/definitions/OperationVariable" + } + }, + "outputVariable": { + "type": "array", + "items": { + "$ref": "#/definitions/OperationVariable" + } + }, + "inoutputVariable": { + "type": "array", + "items": { + "$ref": "#/definitions/OperationVariable" + } + } + } + } + ] + }, + "OperationVariable": { + "type": "object", + "properties": { + "value": { + "oneOf": [ + { + "$ref": "#/definitions/Blob" + }, + { + "$ref": "#/definitions/File" + }, + { + "$ref": "#/definitions/Capability" + }, + { + "$ref": "#/definitions/Entity" + }, + { + "$ref": "#/definitions/Event" + }, + { + "$ref": "#/definitions/BasicEvent" + }, + { + "$ref": "#/definitions/MultiLanguageProperty" + }, + { + "$ref": "#/definitions/Operation" + }, + { + "$ref": "#/definitions/Property" + }, + { + "$ref": "#/definitions/Range" + }, + { + "$ref": "#/definitions/ReferenceElement" + }, + { + "$ref": "#/definitions/RelationshipElement" + }, + { + "$ref": "#/definitions/SubmodelElementCollection" + } + ] + } + }, + "required": [ + "value" + ] + }, + "SubmodelElement": { + "allOf": [ + { + "$ref": "#/definitions/Referable" + }, + { + "$ref": "#/definitions/HasDataSpecification" + }, + { + "$ref": "#/definitions/HasSemantics" + }, + { + "$ref": "#/definitions/Qualifiable" + }, + { + "properties": { + "kind": { + "$ref": "#/definitions/ModelingKind" + }, + "idShort": { + "type": "string" + } + }, + "required": [ + "idShort" + ] + } + ] + }, + "Event": { + "allOf": [ + { + "$ref": "#/definitions/SubmodelElement" + } + ] + }, + "BasicEvent": { + "allOf": [ + { + "$ref": "#/definitions/Event" + }, + { + "properties": { + "observed": { + "$ref": "#/definitions/Reference" + } + }, + "required": [ + "observed" + ] + } + ] + }, + "EntityType": { + "type": "string", + "enum": [ + "CoManagedEntity", + "SelfManagedEntity" + ] + }, + "Entity": { + "allOf": [ + { + "$ref": "#/definitions/SubmodelElement" + }, + { + "properties": { + "statements": { + "type": "array", + "items": { + "$ref": "#/definitions/SubmodelElement" + } + }, + "entityType": { + "$ref": "#/definitions/EntityType" + }, + "globalAssetId": { + "$ref": "#/definitions/Reference" + }, + "specificAssetIds": { + "$ref": "#/definitions/IdentifierKeyValuePair" + } + }, + "required": [ + "entityType" + ] + } + ] + }, + "View": { + "allOf": [ + { + "$ref": "#/definitions/Referable" + }, + { + "$ref": "#/definitions/HasDataSpecification" + }, + { + "$ref": "#/definitions/HasSemantics" + }, + { + "properties": { + "containedElements": { + "type": "array", + "items": { + "$ref": "#/definitions/Reference" + } + } + } + } + ] + }, + "ConceptDescription": { + "allOf": [ + { + "$ref": "#/definitions/Identifiable" + }, + { + "$ref": "#/definitions/HasDataSpecification" + }, + { + "properties": { + "isCaseOf": { + "type": "array", + "items": { + "$ref": "#/definitions/Reference" + } + } + } + } + ] + }, + "Capability": { + "allOf": [ + { + "$ref": "#/definitions/SubmodelElement" + } + ] + }, + "Property": { + "allOf": [ + { + "$ref": "#/definitions/SubmodelElement" + }, + { + "$ref": "#/definitions/ValueObject" + } + ] + }, + "Range": { + "allOf": [ + { + "$ref": "#/definitions/SubmodelElement" + }, + { + "properties": { + "valueType": { + "type": "string", + "enum": [ + "anyUri", + "base64Binary", + "boolean", + "date", + "dateTime", + "dateTimeStamp", + "decimal", + "integer", + "long", + "int", + "short", + "byte", + "nonNegativeInteger", + "positiveInteger", + "unsignedLong", + "unsignedInt", + "unsignedShort", + "unsignedByte", + "nonPositiveInteger", + "negativeInteger", + "double", + "duration", + "dayTimeDuration", + "yearMonthDuration", + "float", + "gDay", + "gMonth", + "gMonthDay", + "gYear", + "gYearMonth", + "hexBinary", + "NOTATION", + "QName", + "string", + "normalizedString", + "token", + "language", + "Name", + "NCName", + "ENTITY", + "ID", + "IDREF", + "NMTOKEN", + "time" + ] + }, + "min": { + "type": "string" + }, + "max": { + "type": "string" + } + }, + "required": [ + "valueType" + ] + } + ] + }, + "MultiLanguageProperty": { + "allOf": [ + { + "$ref": "#/definitions/SubmodelElement" + }, + { + "properties": { + "value": { + "type": "array", + "items": { + "$ref": "#/definitions/LangString" + } + }, + "valueId": { + "$ref": "#/definitions/Reference" + } + } + } + ] + }, + "File": { + "allOf": [ + { + "$ref": "#/definitions/SubmodelElement" + }, + { + "properties": { + "value": { + "type": "string" + }, + "mimeType": { + "type": "string" + } + }, + "required": [ + "mimeType" + ] + } + ] + }, + "Blob": { + "allOf": [ + { + "$ref": "#/definitions/SubmodelElement" + }, + { + "properties": { + "value": { + "type": "string" + }, + "mimeType": { + "type": "string" + } + }, + "required": [ + "mimeType" + ] + } + ] + }, + "ReferenceElement": { + "allOf": [ + { + "$ref": "#/definitions/SubmodelElement" + }, + { + "properties": { + "value": { + "$ref": "#/definitions/Reference" + } + } + } + ] + }, + "SubmodelElementCollection": { + "allOf": [ + { + "$ref": "#/definitions/SubmodelElement" + }, + { + "properties": { + "value": { + "type": "array", + "items": { + "oneOf": [ + { + "$ref": "#/definitions/Blob" + }, + { + "$ref": "#/definitions/File" + }, + { + "$ref": "#/definitions/Capability" + }, + { + "$ref": "#/definitions/Entity" + }, + { + "$ref": "#/definitions/Event" + }, + { + "$ref": "#/definitions/BasicEvent" + }, + { + "$ref": "#/definitions/MultiLanguageProperty" + }, + { + "$ref": "#/definitions/Operation" + }, + { + "$ref": "#/definitions/Property" + }, + { + "$ref": "#/definitions/Range" + }, + { + "$ref": "#/definitions/ReferenceElement" + }, + { + "$ref": "#/definitions/RelationshipElement" + }, + { + "$ref": "#/definitions/SubmodelElementCollection" + } + ] + } + }, + "allowDuplicates": { + "type": "boolean" + }, + "ordered": { + "type": "boolean" + } + } + } + ] + }, + "RelationshipElement": { + "allOf": [ + { + "$ref": "#/definitions/SubmodelElement" + }, + { + "properties": { + "first": { + "$ref": "#/definitions/Reference" + }, + "second": { + "$ref": "#/definitions/Reference" + } + }, + "required": [ + "first", + "second" + ] + } + ] + }, + "AnnotatedRelationshipElement": { + "allOf": [ + { + "$ref": "#/definitions/RelationshipElement" + }, + { + "properties": { + "annotation": { + "type": "array", + "items": { + "oneOf": [ + { + "$ref": "#/definitions/Blob" + }, + { + "$ref": "#/definitions/File" + }, + { + "$ref": "#/definitions/MultiLanguageProperty" + }, + { + "$ref": "#/definitions/Property" + }, + { + "$ref": "#/definitions/Range" + }, + { + "$ref": "#/definitions/ReferenceElement" + } + ] + } + } + } + } + ] + }, + "Qualifier": { + "allOf": [ + { + "$ref": "#/definitions/Constraint" + }, + { + "$ref": "#/definitions/HasSemantics" + }, + { + "$ref": "#/definitions/ValueObject" + }, + { + "properties": { + "type": { + "type": "string" + } + }, + "required": [ + "type" + ] + } + ] + }, + "Formula": { + "allOf": [ + { + "$ref": "#/definitions/Constraint" + }, + { + "properties": { + "dependsOn": { + "type": "array", + "items": { + "$ref": "#/definitions/Reference" + } + } + } + } + ] + }, + "Security": { + "type": "object", + "properties": { + "accessControlPolicyPoints": { + "$ref": "#/definitions/AccessControlPolicyPoints" + }, + "certificate": { + "type": "array", + "items": { + "oneOf": [ + { + "$ref": "#/definitions/BlobCertificate" + } + ] + } + }, + "requiredCertificateExtension": { + "type": "array", + "items": { + "$ref": "#/definitions/Reference" + } + } + }, + "required": [ + "accessControlPolicyPoints" + ] + }, + "Certificate": { + "type": "object" + }, + "BlobCertificate": { + "allOf": [ + { + "$ref": "#/definitions/Certificate" + }, + { + "properties": { + "blobCertificate": { + "$ref": "#/definitions/Blob" + }, + "containedExtension": { + "type": "array", + "items": { + "$ref": "#/definitions/Reference" + } + }, + "lastCertificate": { + "type": "boolean" + } + } + } + ] + }, + "AccessControlPolicyPoints": { + "type": "object", + "properties": { + "policyAdministrationPoint": { + "$ref": "#/definitions/PolicyAdministrationPoint" + }, + "policyDecisionPoint": { + "$ref": "#/definitions/PolicyDecisionPoint" + }, + "policyEnforcementPoint": { + "$ref": "#/definitions/PolicyEnforcementPoint" + }, + "policyInformationPoints": { + "$ref": "#/definitions/PolicyInformationPoints" + } + }, + "required": [ + "policyAdministrationPoint", + "policyDecisionPoint", + "policyEnforcementPoint" + ] + }, + "PolicyAdministrationPoint": { + "type": "object", + "properties": { + "localAccessControl": { + "$ref": "#/definitions/AccessControl" + }, + "externalAccessControl": { + "type": "boolean" + } + }, + "required": [ + "externalAccessControl" + ] + }, + "PolicyInformationPoints": { + "type": "object", + "properties": { + "internalInformationPoint": { + "type": "array", + "items": { + "$ref": "#/definitions/Reference" + } + }, + "externalInformationPoint": { + "type": "boolean" + } + }, + "required": [ + "externalInformationPoint" + ] + }, + "PolicyEnforcementPoint": { + "type": "object", + "properties": { + "externalPolicyEnforcementPoint": { + "type": "boolean" + } + }, + "required": [ + "externalPolicyEnforcementPoint" + ] + }, + "PolicyDecisionPoint": { + "type": "object", + "properties": { + "externalPolicyDecisionPoints": { + "type": "boolean" + } + }, + "required": [ + "externalPolicyDecisionPoints" + ] + }, + "AccessControl": { + "type": "object", + "properties": { + "selectableSubjectAttributes": { + "$ref": "#/definitions/Reference" + }, + "defaultSubjectAttributes": { + "$ref": "#/definitions/Reference" + }, + "selectablePermissions": { + "$ref": "#/definitions/Reference" + }, + "defaultPermissions": { + "$ref": "#/definitions/Reference" + }, + "selectableEnvironmentAttributes": { + "$ref": "#/definitions/Reference" + }, + "defaultEnvironmentAttributes": { + "$ref": "#/definitions/Reference" + }, + "accessPermissionRule": { + "type": "array", + "items": { + "$ref": "#/definitions/AccessPermissionRule" + } + } + } + }, + "AccessPermissionRule": { + "allOf": [ + { + "$ref": "#/definitions/Referable" + }, + { + "$ref": "#/definitions/Qualifiable" + }, + { + "properties": { + "targetSubjectAttributes": { + "type": "array", + "items": { + "$ref": "#/definitions/SubjectAttributes" + }, + "minItems": 1 + }, + "permissionsPerObject": { + "type": "array", + "items": { + "$ref": "#/definitions/PermissionsPerObject" + } + } + }, + "required": [ + "targetSubjectAttributes" + ] + } + ] + }, + "SubjectAttributes": { + "type": "object", + "properties": { + "subjectAttributes": { + "type": "array", + "items": { + "$ref": "#/definitions/Reference" + }, + "minItems": 1 + } + } + }, + "PermissionsPerObject": { + "type": "object", + "properties": { + "object": { + "$ref": "#/definitions/Reference" + }, + "targetObjectAttributes": { + "$ref": "#/definitions/ObjectAttributes" + }, + "permission": { + "type": "array", + "items": { + "$ref": "#/definitions/Permission" + } + } + } + }, + "ObjectAttributes": { + "type": "object", + "properties": { + "objectAttribute": { + "type": "array", + "items": { + "$ref": "#/definitions/Property" + }, + "minItems": 1 + } + } + }, + "Permission": { + "type": "object", + "properties": { + "permission": { + "$ref": "#/definitions/Reference" + }, + "kindOfPermission": { + "type": "string", + "enum": [ + "Allow", + "Deny", + "NotApplicable", + "Undefined" + ] + } + }, + "required": [ + "permission", + "kindOfPermission" + ] + } + } +} \ No newline at end of file diff --git a/src/administrative_information.rs b/src/administrative_information.rs new file mode 100644 index 0000000..43331ea --- /dev/null +++ b/src/administrative_information.rs @@ -0,0 +1,13 @@ +use serde::{Deserialize, Serialize}; + +#[derive(Serialize, Deserialize, Debug, Clone)] +pub struct AdministrativeInformation { + pub version: Option, + pub revision: Option, +} + +impl AdministrativeInformation { + pub fn new(version: Option, revision: Option) -> Self { + Self { version, revision } + } +} diff --git a/src/asset.rs b/src/asset.rs new file mode 100644 index 0000000..7d9dd3c --- /dev/null +++ b/src/asset.rs @@ -0,0 +1,25 @@ +use crate::{ + administrative_information::AdministrativeInformation, category::Category, + embedded_data_specification::EmbeddedDataSpecification, identifier::Identifier, + model_type::ModelType, +}; +use serde::{Deserialize, Serialize}; + +#[derive(Serialize, Deserialize, Debug, Clone)] +#[serde(rename_all = "camelCase")] +pub struct Asset { + // Identifiable + pub identification: Identifier, + #[serde(skip_serializing_if = "Option::is_none")] + pub administration: Option, + + // Referable + pub id_short: String, + pub model_type: ModelType, + #[serde(skip_serializing_if = "Option::is_none")] + pub category: Option, + + // HasDataSpecification + #[serde(skip_serializing_if = "Vec::is_empty")] + pub embedded_data_specification: Vec, +} diff --git a/src/asset_administration_shell.rs b/src/asset_administration_shell.rs new file mode 100644 index 0000000..79f7693 --- /dev/null +++ b/src/asset_administration_shell.rs @@ -0,0 +1,53 @@ +use crate::{ + administrative_information::AdministrativeInformation, asset_information::AssetInformation, + category::Category, embedded_data_specification::EmbeddedDataSpecification, + identifier::Identifier, model_type::ModelType, model_type::ModelTypeName, reference::Reference, +}; +use serde::{Deserialize, Serialize}; + +#[derive(Serialize, Deserialize, Debug, Clone)] +#[serde(rename_all = "camelCase")] +pub struct AssetAdministrationShell { + // AssetAdministrationShell + pub asset_information: AssetInformation, + #[serde(skip_serializing_if = "Option::is_none")] + pub derived_from: Option, + + #[serde(skip_serializing_if = "Vec::is_empty")] + pub submodels: Vec, + + // Identifiable + pub identification: Identifier, + #[serde(skip_serializing_if = "Option::is_none")] + pub administration: Option, + + // Referable + pub id_short: String, + pub model_type: ModelType, + #[serde(skip_serializing_if = "Option::is_none")] + pub category: Option, + + // HasDataSpecification + #[serde(skip_serializing_if = "Vec::is_empty")] + pub embedded_data_specification: Vec, +} + +impl AssetAdministrationShell { + pub fn new( + id_short: String, + asset_information: AssetInformation, + identification: Identifier, + ) -> Self { + Self { + id_short, + asset_information, + identification, + derived_from: None, + submodels: vec![], + administration: None, + model_type: ModelType::new(ModelTypeName::AssetAdministrationShell), + category: None, + embedded_data_specification: vec![], + } + } +} diff --git a/src/asset_information.rs b/src/asset_information.rs new file mode 100644 index 0000000..a829934 --- /dev/null +++ b/src/asset_information.rs @@ -0,0 +1,9 @@ +use serde::{Deserialize, Serialize}; + +use crate::asset_kind::AssetKind; + +#[derive(Serialize, Deserialize, Debug, Clone)] +#[serde(rename_all = "camelCase")] +pub struct AssetInformation { + pub asset_kind: AssetKind, +} diff --git a/src/asset_kind.rs b/src/asset_kind.rs new file mode 100644 index 0000000..7f96d2b --- /dev/null +++ b/src/asset_kind.rs @@ -0,0 +1,7 @@ +use serde::{Deserialize, Serialize}; + +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq)] +pub enum AssetKind { + Type, + Instance, +} diff --git a/src/bin/aascheck.rs b/src/bin/aascheck.rs new file mode 100644 index 0000000..89a984e --- /dev/null +++ b/src/bin/aascheck.rs @@ -0,0 +1,108 @@ +use std::{ + path::{Path, PathBuf}, + str::FromStr, +}; + +use clap::Parser; +use color_eyre::eyre::{Context, Result}; +use colored::Colorize; +use jsonschema::JSONSchema; +use serde_json::{json, Value}; +use thiserror::Error; + +#[derive(Parser)] +#[clap( + version = "0.1", + author = "Andreas Schmidt " +)] +struct Opts { + #[clap(parse(from_os_str))] + input: PathBuf, + #[clap(short, long)] + mode: Mode, +} + +#[allow(clippy::upper_case_acronyms)] +#[derive(Clone, Copy)] +enum Mode { + AAS, + Submodel, +} + +impl FromStr for Mode { + type Err = AASCheckError; + + fn from_str(s: &str) -> Result { + match s.to_lowercase().as_str() { + "aas" => Ok(Mode::AAS), + "submodel" => Ok(Mode::Submodel), + _ => Err(AASCheckError::InvalidMode(s.to_string())), + } + } +} + +#[derive(Error, Debug)] +pub enum AASCheckError { + #[error("{0}")] + InvalidMode(String), +} + +fn main() -> Result<()> { + let opt = Opts::parse(); + let instance = read_json(&opt.input)?; + let schema = static_json()?; + let compiled = JSONSchema::compile(&schema)?; + check(&compiled, instance, opt.mode)?; + output(&opt.input, opt.mode); + Ok(()) +} + +fn check(schema: &JSONSchema, instance: Value, mode: Mode) -> Result<()> { + let instance = match mode { + Mode::AAS => instance, + Mode::Submodel => { + json!({ + "assetAdministrationShells": [], + "submodels": [ + instance + ], + "assets": [], + "conceptDescriptions": [] + }) + } + }; + let result = match schema.validate(&instance) { + Ok(_) => Ok(()), + Err(errors) => { + let text = errors + .into_iter() + .map(|e| format!("{:#?}", e)) + .collect::>() + .join("\n"); + Err(color_eyre::eyre::anyhow!(text).wrap_err("Validation failed!")) + } + }; + result +} + +fn read_json(path: &Path) -> Result { + let content = + std::fs::read_to_string(path).wrap_err(format!("Opening file: {}", path.display()))?; + Ok(serde_json::from_str(&content)?) +} + +fn static_json() -> Result { + let content = include_str!("../../schema/aas.json"); + Ok(serde_json::from_str(content)?) +} + +fn output(path: &Path, mode: Mode) { + let t = match mode { + Mode::AAS => "Asset Administration Shell", + Mode::Submodel => "Submodel of an Asset Administration Shell", + } + .bold(); + let path = format!("{}", path.display()).bold(); + let text = format!("{} is a valid {}", path, t).green(); + println!("{}", text); +} diff --git a/src/category.rs b/src/category.rs new file mode 100644 index 0000000..6bddab5 --- /dev/null +++ b/src/category.rs @@ -0,0 +1,24 @@ +use serde::{Deserialize, Serialize}; + +#[derive(Serialize, Deserialize, Debug, Clone)] +pub enum Category { + VARIABLE, + PARAMETER, + CONSTANT, +} + +impl Category { + pub fn get(cat: String) -> Category { + match cat.as_str() { + "VARIABLE" => Category::VARIABLE, + "PARAMETER" => Category::PARAMETER, + "CONSTANT" => Category::CONSTANT, + _ => Category::default(), + } + } +} +impl Default for Category { + fn default() -> Self { + Category::CONSTANT + } +} diff --git a/src/concept_description.rs b/src/concept_description.rs new file mode 100644 index 0000000..1bee296 --- /dev/null +++ b/src/concept_description.rs @@ -0,0 +1,45 @@ +use crate::{ + administrative_information::AdministrativeInformation, + category::Category, + embedded_data_specification::EmbeddedDataSpecification, + identifier::Identifier, + model_type::{ModelType, ModelTypeName}, + reference::Reference, +}; +use serde::{Deserialize, Serialize}; + +#[derive(Serialize, Deserialize, Debug, Clone)] +#[serde(rename_all = "camelCase")] +pub struct ConceptDescription { + // ConceptDescription + pub is_case_of: Option, + + // Identifiable + pub identification: Identifier, + #[serde(skip_serializing_if = "Option::is_none")] + pub administration: Option, + + // Referable + pub id_short: String, + pub model_type: ModelType, + #[serde(skip_serializing_if = "Option::is_none")] + pub category: Option, + + // HasDataSpecification + #[serde(skip_serializing_if = "Vec::is_empty")] + pub embedded_data_specification: Vec, +} + +impl ConceptDescription { + pub fn new(id_short: String, identification: Identifier) -> Self { + Self { + identification, + administration: None, + id_short, + category: None, + model_type: ModelType::new(ModelTypeName::ConceptDescription), + embedded_data_specification: vec![], + is_case_of: None, + } + } +} diff --git a/src/data_object_type_name.rs b/src/data_object_type_name.rs new file mode 100644 index 0000000..72ce23d --- /dev/null +++ b/src/data_object_type_name.rs @@ -0,0 +1,76 @@ +use serde::{Deserialize, Serialize}; + +#[derive(Serialize, Deserialize, Clone, Debug)] +#[serde(rename_all = "camelCase")] +pub enum DataObjectTypeName { + Boolean, + Double, + Int, + Integer, + AnyType, + ComplexType, + Date, + DateTime, + Decimal, + Short, + Byte, + Duration, + String, + Time, + HexBinary, + Float, +} + +impl DataObjectTypeName { + pub fn get(value_type: String) -> DataObjectTypeName { + match value_type.as_str().to_lowercase().as_str() { + "boolean" => DataObjectTypeName::Boolean, + "double" => DataObjectTypeName::Double, + "int" => DataObjectTypeName::Int, + "short" => DataObjectTypeName::Short, + "byte" => DataObjectTypeName::Byte, + "string" => DataObjectTypeName::String, + "time" => DataObjectTypeName::Time, + "duration" => DataObjectTypeName::Duration, + "decimal" => DataObjectTypeName::Decimal, + "hexbinary" => DataObjectTypeName::HexBinary, + "datetime" => DataObjectTypeName::DateTime, + "date" => DataObjectTypeName::Date, + "complextype" => DataObjectTypeName::ComplexType, + "anytype" => DataObjectTypeName::AnyType, + "integer" => DataObjectTypeName::Integer, + "float" => DataObjectTypeName::Float, + _ => DataObjectTypeName::default(), + } + } +} + +impl Default for DataObjectTypeName { + fn default() -> Self { + DataObjectTypeName::Boolean + } +} + +impl ToString for DataObjectTypeName { + fn to_string(&self) -> std::string::String { + let s = match self { + DataObjectTypeName::Boolean => "boolean", + DataObjectTypeName::Double => "double", + DataObjectTypeName::Int => "int", + DataObjectTypeName::Short => "short", + DataObjectTypeName::Byte => "byte", + DataObjectTypeName::String => "string", + DataObjectTypeName::Time => "time", + DataObjectTypeName::Duration => "duration", + DataObjectTypeName::Decimal => "decimal", + DataObjectTypeName::HexBinary => "hexBinary", + DataObjectTypeName::DateTime => "dateTime", + DataObjectTypeName::Date => "date", + DataObjectTypeName::ComplexType => "complexType", + DataObjectTypeName::AnyType => "anyType", + DataObjectTypeName::Integer => "integer", + DataObjectTypeName::Float => "float", + }; + s.to_string() + } +} diff --git a/src/embedded_data_specification.rs b/src/embedded_data_specification.rs new file mode 100644 index 0000000..7c8c165 --- /dev/null +++ b/src/embedded_data_specification.rs @@ -0,0 +1,7 @@ +use serde::{Deserialize, Serialize}; + +#[derive(Serialize, Deserialize, Debug, Clone)] +#[serde(rename_all = "camelCase")] +pub struct EmbeddedDataSpecification { + // TODO +} diff --git a/src/environment.rs b/src/environment.rs new file mode 100644 index 0000000..f1519de --- /dev/null +++ b/src/environment.rs @@ -0,0 +1,17 @@ +use crate::concept_description::ConceptDescription; +use crate::submodel::Submodel; +use crate::{asset::Asset, asset_administration_shell::AssetAdministrationShell}; +use serde::{Deserialize, Serialize}; + +#[derive(Serialize, Deserialize, Debug, Clone)] +#[serde(rename_all = "camelCase")] +pub struct Environment { + #[serde(skip_serializing_if = "Vec::is_empty")] + pub asset_administration_shells: Vec, + #[serde(skip_serializing_if = "Vec::is_empty")] + pub submodels: Vec, + #[serde(skip_serializing_if = "Vec::is_empty")] + pub assets: Vec, + #[serde(skip_serializing_if = "Vec::is_empty")] + pub concept_descriptions: Vec, +} diff --git a/src/error.rs b/src/error.rs new file mode 100644 index 0000000..ae8d04a --- /dev/null +++ b/src/error.rs @@ -0,0 +1,18 @@ +use crate::DataObjectTypeName; +use std::{ + num::{ParseFloatError, ParseIntError}, + str::ParseBoolError, +}; +use thiserror::Error; + +#[derive(Error, Debug)] +pub enum AASError { + #[error("{0}")] + ParseBoolError(#[from] ParseBoolError), + #[error("{0}")] + ParseIntError(#[from] ParseIntError), + #[error("{0}")] + ParseFloatError(#[from] ParseFloatError), + #[error("Unsupported Type: {0:?}")] + UnsupportedType(DataObjectTypeName), +} diff --git a/src/identifier.rs b/src/identifier.rs new file mode 100644 index 0000000..d0464da --- /dev/null +++ b/src/identifier.rs @@ -0,0 +1,15 @@ +use crate::key_type::KeyType; +use serde::{Deserialize, Serialize}; + +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq)] +#[serde(rename_all = "camelCase")] +pub struct Identifier { + pub id_type: KeyType, + pub id: String, +} + +impl Identifier { + pub fn new(id_type: KeyType, id: String) -> Self { + Self { id_type, id } + } +} diff --git a/src/key.rs b/src/key.rs new file mode 100644 index 0000000..269cd2d --- /dev/null +++ b/src/key.rs @@ -0,0 +1,24 @@ +use crate::key_type::KeyType; +use serde::{Deserialize, Serialize}; + +#[derive(Serialize, Deserialize, Debug, Clone)] +#[serde(rename_all = "camelCase")] +pub struct Key { + pub r#type: String, + pub value: String, + pub id_type: KeyType, + pub local: Option, + pub index: Option, +} + +impl Key { + pub fn new(r#type: String, value: String, id_type: KeyType) -> Self { + Self { + r#type, + local: None, + value, + index: None, + id_type, + } + } +} diff --git a/src/key_type.rs b/src/key_type.rs new file mode 100644 index 0000000..bbbe226 --- /dev/null +++ b/src/key_type.rs @@ -0,0 +1,33 @@ +use serde::{Deserialize, Serialize}; + +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq)] +pub enum KeyType { + IRI, + IRDI, + IdShort, + FragmentId, + Custom, +} + +impl KeyType {} + +impl std::str::FromStr for KeyType { + type Err = (); + + fn from_str(s: &str) -> Result { + Ok(match s { + "IRI" => KeyType::IRI, + "IRDI" => KeyType::IRDI, + "IdShort" => KeyType::IdShort, + "FragmentId" => KeyType::FragmentId, + "Custom" => KeyType::Custom, + _ => return Err(()), + }) + } +} + +impl Default for KeyType { + fn default() -> KeyType { + KeyType::IdShort + } +} diff --git a/src/lang_string.rs b/src/lang_string.rs new file mode 100644 index 0000000..a200dad --- /dev/null +++ b/src/lang_string.rs @@ -0,0 +1,13 @@ +use serde::{Deserialize, Serialize}; + +#[derive(Serialize, Deserialize, Debug, Clone)] +pub struct LangString { + pub language: String, + pub text: String, +} + +impl LangString { + pub fn new(language: String, text: String) -> Self { + Self { language, text } + } +} diff --git a/src/lib.rs b/src/lib.rs new file mode 100644 index 0000000..8ac9f75 --- /dev/null +++ b/src/lib.rs @@ -0,0 +1,71 @@ +//! # A Rust library to work with Asset Administration Shells (AAS) +//! +//! # Examples +//! +//! ## Creating a Submodel and Serialize to JSON +//! ```no_run +//! use basyx_rs::prelude::*; +//! +//! let mut property = Property::new( +//! "property".into(), +//! Some(Value::Boolean(false)), +//! DataObjectTypeName::Boolean, +//! ); +//! property.category = Some(Category::CONSTANT); +//! property.kind = Some(ModelingKind::Instance); +//! +//! let sme = SubmodelElement::SMProperty(property); + +//! let submodel = Submodel::new("submodel1".into(), KeyType::IdShort, "i".into(), vec![sme]); +//! +//! let json = serde_json::to_vec(&submodel)?; +//! let mut file = std::fs::OpenOptions::new() +//! .create(true) +//! .write(true) +//! .read(true) +//! .truncate(true) +//! .open(path"submodel1.json")?; +//! file.write_all(&json)?; +//! ``` + +mod administrative_information; +mod asset; +mod asset_administration_shell; +mod asset_information; +mod asset_kind; +mod category; +mod concept_description; +mod data_object_type_name; +mod embedded_data_specification; +mod environment; +mod error; +mod identifier; +mod key; +mod key_type; +mod lang_string; +mod model_type; +mod modeling_kind; +pub mod prelude; +mod reference; +mod submodel; +pub mod submodel_element; +mod value; + +pub use administrative_information::AdministrativeInformation; +pub use asset::Asset; +pub use asset_administration_shell::AssetAdministrationShell; +pub use asset_information::AssetInformation; +pub use asset_kind::AssetKind; +pub use category::Category; +pub use concept_description::ConceptDescription; +pub use data_object_type_name::DataObjectTypeName; +pub use environment::Environment; +pub use identifier::Identifier; +pub use key::Key; +pub use key_type::KeyType; +pub use lang_string::LangString; +pub use model_type::{ModelType, ModelTypeName}; +pub use modeling_kind::ModelingKind; +pub use reference::Reference; +pub use submodel::Submodel; +pub use value::Value; diff --git a/src/model_type.rs b/src/model_type.rs new file mode 100644 index 0000000..ed7dbbe --- /dev/null +++ b/src/model_type.rs @@ -0,0 +1,34 @@ +use serde::{Deserialize, Serialize}; + +#[derive(Serialize, Deserialize, Debug, Clone)] +pub enum ModelTypeName { + Asset, + AssetAdministrationShell, + BasicEvent, + ConceptDescription, + Event, + File, + Operation, + OperationVariable, + Property, + Qualifier, + Range, + ReferenceElement, + Submodel, + SubmodelElementCollection, +} + +#[derive(Serialize, Deserialize, Debug, Clone)] +pub struct ModelType { + name: ModelTypeName, +} + +impl ModelType { + pub fn new(type_name: ModelTypeName) -> Self { + Self { name: type_name } + } + + pub fn name(&self) -> ModelTypeName { + self.name.clone() + } +} diff --git a/src/modeling_kind.rs b/src/modeling_kind.rs new file mode 100644 index 0000000..e1bf2c1 --- /dev/null +++ b/src/modeling_kind.rs @@ -0,0 +1,27 @@ +use std::str::FromStr; + +use serde::{Deserialize, Serialize}; + +#[derive(Serialize, Deserialize, Debug, Clone)] +pub enum ModelingKind { + Template, + Instance, +} + +impl FromStr for ModelingKind { + type Err = (); + + fn from_str(s: &str) -> Result { + Ok(match s { + "Instance" => ModelingKind::Instance, + "Template" => ModelingKind::Template, + _ => return Err(()), + }) + } +} + +impl Default for ModelingKind { + fn default() -> Self { + ModelingKind::Instance + } +} diff --git a/src/prelude.rs b/src/prelude.rs new file mode 100644 index 0000000..38917a3 --- /dev/null +++ b/src/prelude.rs @@ -0,0 +1,10 @@ +pub use crate::{ + AdministrativeInformation, Category, ConceptDescription, DataObjectTypeName, Environment, + Identifier, Key, KeyType, LangString, ModelType, ModelTypeName, ModelingKind, Reference, + Submodel, Value, +}; + +pub use crate::submodel_element::{ + BasicEvent, Operation, OperationVariable, Property, Qualifier, Range, ReferenceElement, + SubmodelElement, SubmodelElementCollection, Variable, +}; diff --git a/src/reference.rs b/src/reference.rs new file mode 100644 index 0000000..c73b891 --- /dev/null +++ b/src/reference.rs @@ -0,0 +1,21 @@ +use serde::{Deserialize, Serialize}; + +use crate::key::Key; + +#[derive(Serialize, Deserialize, Debug, Clone)] +#[serde(rename_all = "camelCase")] +pub struct Reference { + pub keys: Vec, +} + +impl Reference { + pub fn from_keys(keys: Vec) -> Self { + Self { keys } + } +} + +impl Default for Reference { + fn default() -> Self { + Self::from_keys(vec![]) + } +} diff --git a/src/submodel.rs b/src/submodel.rs new file mode 100644 index 0000000..e50dcc4 --- /dev/null +++ b/src/submodel.rs @@ -0,0 +1,64 @@ +use crate::administrative_information::AdministrativeInformation; +use crate::category::Category; +use crate::embedded_data_specification::EmbeddedDataSpecification; +use crate::identifier::Identifier; +use crate::key_type::KeyType; +use crate::model_type::{ModelType, ModelTypeName}; +use crate::modeling_kind::ModelingKind; +use crate::reference::Reference; +use crate::submodel_element::{Qualifier, SubmodelElement}; +use serde::{Deserialize, Serialize}; + +#[derive(Serialize, Deserialize, Debug, Clone)] +#[serde(rename_all = "camelCase")] +pub struct Submodel { + // Submodel + pub submodel_elements: Vec, + #[serde(skip_serializing_if = "Option::is_none")] + pub kind: Option, + + // Identifiable + pub identification: Identifier, + #[serde(skip_serializing_if = "Option::is_none")] + pub administration: Option, + + // Referable + pub id_short: String, + pub model_type: ModelType, + #[serde(skip_serializing_if = "Option::is_none")] + pub category: Option, + + // HasDataSpecification + #[serde(skip_serializing_if = "Vec::is_empty")] + pub embedded_data_specification: Vec, + + // Qualifiable + #[serde(skip_serializing_if = "Vec::is_empty")] + pub qualifiers: Vec, + + // HasSemantics + #[serde(skip_serializing_if = "Option::is_none")] + pub semantic_id: Option, +} + +impl Submodel { + pub fn new( + id: String, + id_type: KeyType, + id_short: String, + submodel_elements: Vec, + ) -> Self { + Self { + id_short, + submodel_elements, + semantic_id: None, + qualifiers: vec![], + embedded_data_specification: vec![], + identification: Identifier { id_type, id }, + administration: None, + category: None, + model_type: ModelType::new(ModelTypeName::Submodel), + kind: None, + } + } +} diff --git a/src/submodel_element/basic_event.rs b/src/submodel_element/basic_event.rs new file mode 100644 index 0000000..c897227 --- /dev/null +++ b/src/submodel_element/basic_event.rs @@ -0,0 +1,53 @@ +use super::EmbeddedDataSpecification; +use crate::{ + category::Category, + model_type::{ModelType, ModelTypeName}, + modeling_kind::ModelingKind, + reference::Reference, + submodel_element::qualifier::Qualifier, +}; +use serde::{Deserialize, Serialize}; + +#[derive(Serialize, Deserialize, Debug, Clone)] +#[serde(rename_all = "camelCase")] +pub struct BasicEvent { + // BasicEvent + pub observed: Reference, + + // SubmodelElement + pub id_short: String, + #[serde(skip_serializing_if = "Option::is_none")] + pub kind: Option, + + // Referable + pub model_type: ModelType, + #[serde(skip_serializing_if = "Option::is_none")] + pub category: Option, + + // HasDataSpecification + #[serde(skip_serializing_if = "Vec::is_empty")] + pub embedded_data_specification: Vec, + + // HasSemantics + #[serde(skip_serializing_if = "Option::is_none")] + pub semantic_id: Option, + + // Qualifiable + #[serde(skip_serializing_if = "Vec::is_empty")] + pub qualifiers: Vec, +} + +impl BasicEvent { + pub fn new(id_short: String, observed: Reference) -> Self { + Self { + observed, + semantic_id: None, + embedded_data_specification: vec![], + id_short, + category: None, + qualifiers: vec![], + model_type: ModelType::new(ModelTypeName::Event), + kind: None, + } + } +} diff --git a/src/submodel_element/data_object_type.rs b/src/submodel_element/data_object_type.rs new file mode 100644 index 0000000..4d5ea21 --- /dev/null +++ b/src/submodel_element/data_object_type.rs @@ -0,0 +1,13 @@ +use crate::DataObjectTypeName; +use serde::{Deserialize, Serialize}; + +#[derive(Serialize, Deserialize, Debug, Clone)] +pub struct DataObjectType { + pub name: DataObjectTypeName, +} + +impl DataObjectType { + pub fn new(name: DataObjectTypeName) -> Self { + Self { name } + } +} diff --git a/src/submodel_element/data_specification_content.rs b/src/submodel_element/data_specification_content.rs new file mode 100644 index 0000000..3016be5 --- /dev/null +++ b/src/submodel_element/data_specification_content.rs @@ -0,0 +1,41 @@ +use crate::{reference::Reference, LangString}; +use serde::{Deserialize, Serialize}; + +#[derive(Serialize, Deserialize, Debug, Clone)] +#[serde(rename_all = "camelCase")] +pub struct DataSpecificationContent { + pub preferred_name: Vec, + + #[serde(skip_serializing_if = "Option::is_none")] + pub data_type: Option, + #[serde(skip_serializing_if = "Vec::is_empty")] + pub definition: Vec, + #[serde(skip_serializing_if = "Vec::is_empty")] + pub short_name: Vec, + #[serde(skip_serializing_if = "Option::is_none")] + pub source_of_definition: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub symbol: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub unit: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub unit_id: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub value_format: Option, +} + +impl DataSpecificationContent { + pub fn new(preferred_name: Vec) -> Self { + Self { + preferred_name, + short_name: vec![], + unit: None, + unit_id: None, + value_format: None, + source_of_definition: None, + symbol: None, + data_type: None, + definition: vec![], + } + } +} diff --git a/src/submodel_element/embedded_data_specification.rs b/src/submodel_element/embedded_data_specification.rs new file mode 100644 index 0000000..3ef3b81 --- /dev/null +++ b/src/submodel_element/embedded_data_specification.rs @@ -0,0 +1,22 @@ +use super::data_specification_content::DataSpecificationContent; +use crate::reference::Reference; +use serde::{Deserialize, Serialize}; + +#[derive(Serialize, Deserialize, Debug, Clone)] +#[serde(rename_all = "camelCase")] +pub struct EmbeddedDataSpecification { + pub data_specification: Reference, + pub data_specification_content: DataSpecificationContent, +} + +impl EmbeddedDataSpecification { + pub fn new( + data_specification: Reference, + data_specification_content: DataSpecificationContent, + ) -> Self { + Self { + data_specification, + data_specification_content, + } + } +} diff --git a/src/submodel_element/file.rs b/src/submodel_element/file.rs new file mode 100644 index 0000000..e238c2c --- /dev/null +++ b/src/submodel_element/file.rs @@ -0,0 +1,55 @@ +use super::{qualifier::Qualifier, EmbeddedDataSpecification}; +use crate::{ + category::Category, + model_type::{ModelType, ModelTypeName}, + modeling_kind::ModelingKind, + reference::Reference, +}; +use serde::{Deserialize, Serialize}; + +#[derive(Serialize, Deserialize, Debug, Clone)] +#[serde(rename_all = "camelCase")] +pub struct File { + // File + pub mime_type: String, + #[serde(skip_serializing_if = "Option::is_none")] + pub value: Option, + + // SubmodelElement + pub id_short: String, + #[serde(skip_serializing_if = "Option::is_none")] + pub kind: Option, + + // Referable + pub model_type: ModelType, + #[serde(skip_serializing_if = "Option::is_none")] + pub category: Option, + + // HasDataSpecification + #[serde(skip_serializing_if = "Vec::is_empty")] + pub embedded_data_specification: Vec, + + // HasSemantics + #[serde(skip_serializing_if = "Option::is_none")] + pub semantic_id: Option, + + // Qualifiable + #[serde(skip_serializing_if = "Vec::is_empty")] + pub qualifiers: Vec, +} + +impl File { + pub fn new(id_short: String, mime_type: String) -> Self { + Self { + id_short, + model_type: ModelType::new(ModelTypeName::File), + mime_type, + kind: None, + embedded_data_specification: vec![], + category: None, + semantic_id: None, + qualifiers: vec![], + value: None, + } + } +} diff --git a/src/submodel_element/mod.rs b/src/submodel_element/mod.rs new file mode 100644 index 0000000..08804bf --- /dev/null +++ b/src/submodel_element/mod.rs @@ -0,0 +1,55 @@ +mod basic_event; +mod data_object_type; +pub mod data_specification_content; +mod embedded_data_specification; +mod file; +mod operation; +mod operation_variable; +mod property; +mod qualifier; +mod range; +mod reference_element; +mod submodel_element_collection; +mod value_type; +mod variable; + +pub use basic_event::BasicEvent; +pub use data_object_type::DataObjectType; +pub use embedded_data_specification::EmbeddedDataSpecification; +pub use file::File; +pub use operation::Operation; +pub use operation_variable::OperationVariable; +pub use property::Property; +pub use qualifier::Qualifier; +pub use range::Range; +pub use reference_element::ReferenceElement; +use serde::{Deserialize, Serialize}; +pub use submodel_element_collection::SubmodelElementCollection; +pub use value_type::ValueType; +pub use variable::Variable; + +#[derive(Serialize, Deserialize, Debug, Clone)] +#[serde(untagged)] +pub enum SubmodelElement { + SMCollection(SubmodelElementCollection), + SMEvent(BasicEvent), + SMFile(File), + SMOperation(Operation), + SMProperty(Property), + SMRange(Range), + SMReferenceElement(ReferenceElement), +} + +impl SubmodelElement { + pub fn get_id_short(&self) -> String { + match self { + SubmodelElement::SMCollection(coll) => coll.id_short.clone(), + SubmodelElement::SMEvent(coll) => coll.id_short.clone(), + SubmodelElement::SMFile(coll) => coll.id_short.clone(), + SubmodelElement::SMOperation(coll) => coll.id_short.clone(), + SubmodelElement::SMProperty(coll) => coll.id_short.clone(), + SubmodelElement::SMRange(coll) => coll.id_short.clone(), + SubmodelElement::SMReferenceElement(coll) => coll.id_short.clone(), + } + } +} diff --git a/src/submodel_element/operation.rs b/src/submodel_element/operation.rs new file mode 100644 index 0000000..810b8b0 --- /dev/null +++ b/src/submodel_element/operation.rs @@ -0,0 +1,64 @@ +use super::{variable::Variable, EmbeddedDataSpecification}; +use crate::{ + category::Category, + model_type::{ModelType, ModelTypeName}, + modeling_kind::ModelingKind, + reference::Reference, + submodel_element::Qualifier, +}; +use serde::{Deserialize, Serialize}; + +#[derive(Serialize, Deserialize, Debug, Clone)] +#[serde(rename_all = "camelCase")] +pub struct Operation { + // Operation + #[serde(skip_serializing_if = "Vec::is_empty")] + pub input_variable: Vec, + #[serde(skip_serializing_if = "Vec::is_empty")] + pub output_variable: Vec, + #[serde(skip_serializing_if = "Vec::is_empty")] + pub inoutput_variable: Vec, + + // SubmodelElement + pub id_short: String, + #[serde(skip_serializing_if = "Option::is_none")] + pub kind: Option, + + // Referable + pub model_type: ModelType, + #[serde(skip_serializing_if = "Option::is_none")] + pub category: Option, + + // HasDataSpecification + #[serde(skip_serializing_if = "Vec::is_empty")] + pub embedded_data_specification: Vec, + + // HasSemantics + #[serde(skip_serializing_if = "Option::is_none")] + pub semantic_id: Option, + + // Qualifiable + #[serde(skip_serializing_if = "Vec::is_empty")] + pub qualifiers: Vec, +} + +impl Operation { + pub fn new( + id_short: String, + input_variable: Vec, + output_variable: Vec, + ) -> Self { + Self { + id_short, + model_type: ModelType::new(ModelTypeName::Operation), + input_variable, + output_variable, + inoutput_variable: vec![], + semantic_id: None, + embedded_data_specification: vec![], + category: None, + kind: None, + qualifiers: vec![], + } + } +} diff --git a/src/submodel_element/operation_variable.rs b/src/submodel_element/operation_variable.rs new file mode 100644 index 0000000..9ddd361 --- /dev/null +++ b/src/submodel_element/operation_variable.rs @@ -0,0 +1,14 @@ +use super::SubmodelElement; +use serde::{Deserialize, Serialize}; + +#[derive(Serialize, Deserialize, Debug, Clone)] +#[serde(rename_all = "camelCase")] +pub struct OperationVariable { + pub submodel_element: SubmodelElement, +} + +impl OperationVariable { + pub fn new(submodel_element: SubmodelElement) -> Self { + Self { submodel_element } + } +} diff --git a/src/submodel_element/property.rs b/src/submodel_element/property.rs new file mode 100644 index 0000000..defaf20 --- /dev/null +++ b/src/submodel_element/property.rs @@ -0,0 +1,80 @@ +use super::{EmbeddedDataSpecification, Qualifier}; +use crate::{ + category::Category, + model_type::{ModelType, ModelTypeName}, + modeling_kind::ModelingKind, + reference::Reference, + DataObjectTypeName, Value, +}; +use serde::{Deserialize, Serialize}; + +#[cfg(feature = "explorer")] +use super::ValueType; + +#[derive(Serialize, Deserialize, Debug, Clone)] +#[serde(rename_all = "camelCase")] +pub struct Property { + // Property + #[cfg(feature = "explorer")] + pub value: String, + #[cfg(not(feature = "explorer"))] + #[serde(skip_serializing_if = "Option::is_none")] + pub value: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub value_id: Option, + #[cfg(feature = "explorer")] + pub value_type: ValueType, + #[cfg(not(feature = "explorer"))] + pub value_type: String, + + // SubmodelElement + pub id_short: String, + #[serde(skip_serializing_if = "Option::is_none")] + pub kind: Option, + + // Referable + pub model_type: ModelType, + #[serde(skip_serializing_if = "Option::is_none")] + pub category: Option, + + // HasDataSpecification + #[serde(skip_serializing_if = "Vec::is_empty")] + pub embedded_data_specification: Vec, + + // HasSemantics + #[serde(skip_serializing_if = "Option::is_none")] + pub semantic_id: Option, + + // Qualifiable + #[serde(skip_serializing_if = "Vec::is_empty")] + pub qualifiers: Vec, +} + +impl Property { + pub fn new(id_short: String, value: Option, value_type: DataObjectTypeName) -> Self { + Self { + #[cfg(feature = "explorer")] + value: { + if let Some(v) = value { + v.to_string() + } else { + String::from("") + } + }, + #[cfg(not(feature = "explorer"))] + value, + value_id: None, + semantic_id: None, + id_short, + category: None, + model_type: ModelType::new(ModelTypeName::Property), + #[cfg(feature = "explorer")] + value_type: ValueType::new(value_type), + #[cfg(not(feature = "explorer"))] + value_type: value_type.to_string(), + embedded_data_specification: vec![], + qualifiers: vec![], + kind: None, + } + } +} diff --git a/src/submodel_element/qualifier.rs b/src/submodel_element/qualifier.rs new file mode 100644 index 0000000..0388aad --- /dev/null +++ b/src/submodel_element/qualifier.rs @@ -0,0 +1,47 @@ +use crate::{ + key::Key, + model_type::{ModelType, ModelTypeName}, + reference::Reference, +}; +use serde::{Deserialize, Serialize}; + +#[derive(Serialize, Deserialize, Debug, Clone)] +#[serde(rename_all = "camelCase")] +pub struct Qualifier { + // Qualifier + pub r#type: String, + + // Constraint + pub model_type: ModelType, + + // HasSemantics + #[serde(skip_serializing_if = "Option::is_none")] + pub semantic_id: Option, + + // ValueObject + pub keys: Vec, + pub value_type: String, + #[serde(skip_serializing_if = "Option::is_none")] + pub value_id: Option, + pub value: String, +} + +impl Qualifier { + pub fn new( + keys: Vec, + r#type: String, + value_type: String, + value_id: Option, + value: String, + ) -> Self { + Self { + semantic_id: None, + keys, + r#type, + value_type, + value_id, + value, + model_type: ModelType::new(ModelTypeName::Qualifier), + } + } +} diff --git a/src/submodel_element/range.rs b/src/submodel_element/range.rs new file mode 100644 index 0000000..d014aae --- /dev/null +++ b/src/submodel_element/range.rs @@ -0,0 +1,94 @@ +use super::{EmbeddedDataSpecification, Qualifier}; +use crate::{ + category::Category, model_type::ModelType, model_type::ModelTypeName, + modeling_kind::ModelingKind, reference::Reference, DataObjectTypeName, Value, +}; +use serde::{Deserialize, Serialize}; + +#[cfg(feature = "explorer")] +use super::ValueType; + +#[derive(Serialize, Deserialize, Debug, Clone)] +#[serde(rename_all = "camelCase")] +pub struct Range { + // Range + #[cfg(feature = "explorer")] + pub min: String, + #[cfg(not(feature = "explorer"))] + #[serde(skip_serializing_if = "Option::is_none")] + pub min: Option, + #[cfg(feature = "explorer")] + pub max: String, + #[cfg(not(feature = "explorer"))] + #[serde(skip_serializing_if = "Option::is_none")] + pub max: Option, + #[cfg(feature = "explorer")] + pub value_type: ValueType, + #[cfg(not(feature = "explorer"))] + pub value_type: String, + + // SubmodelElement + pub id_short: String, + #[serde(skip_serializing_if = "Option::is_none")] + pub kind: Option, + + // Referable + pub model_type: ModelType, + #[serde(skip_serializing_if = "Option::is_none")] + pub category: Option, + + // HasDataSpecification + #[serde(skip_serializing_if = "Vec::is_empty")] + pub embedded_data_specification: Vec, + + // HasSemantics + #[serde(skip_serializing_if = "Option::is_none")] + pub semantic_id: Option, + + // Qualifiable + #[serde(skip_serializing_if = "Vec::is_empty")] + pub qualifiers: Vec, +} + +impl Range { + pub fn new( + id_short: String, + min: Option, + max: Option, + value_type: DataObjectTypeName, + ) -> Self { + Self { + #[cfg(feature = "explorer")] + min: { + if let Some(v) = min { + v.to_string() + } else { + String::from("") + } + }, + #[cfg(not(feature = "explorer"))] + min, + #[cfg(feature = "explorer")] + max: { + if let Some(v) = max { + v.to_string() + } else { + String::from("") + } + }, + #[cfg(not(feature = "explorer"))] + max, + semantic_id: None, + embedded_data_specification: vec![], + id_short, + category: None, + model_type: ModelType::new(ModelTypeName::Range), + #[cfg(feature = "explorer")] + value_type: ValueType::new(value_type), + #[cfg(not(feature = "explorer"))] + value_type: value_type.to_string(), + kind: None, + qualifiers: vec![], + } + } +} diff --git a/src/submodel_element/reference_element.rs b/src/submodel_element/reference_element.rs new file mode 100644 index 0000000..ec21b05 --- /dev/null +++ b/src/submodel_element/reference_element.rs @@ -0,0 +1,52 @@ +use super::{EmbeddedDataSpecification, Qualifier}; +use crate::{ + category::Category, + model_type::{ModelType, ModelTypeName}, + modeling_kind::ModelingKind, + reference::Reference, +}; +use serde::{Deserialize, Serialize}; + +#[derive(Serialize, Deserialize, Debug, Clone)] +#[serde(rename_all = "camelCase")] +pub struct ReferenceElement { + // ReferenceElement + pub value: Option, + + // SubmodelElement + pub id_short: String, + #[serde(skip_serializing_if = "Option::is_none")] + pub kind: Option, + + // Referable + pub model_type: ModelType, + #[serde(skip_serializing_if = "Option::is_none")] + pub category: Option, + + // HasDataSpecification + #[serde(skip_serializing_if = "Vec::is_empty")] + pub embedded_data_specification: Vec, + + // HasSemantics + #[serde(skip_serializing_if = "Option::is_none")] + pub semantic_id: Option, + + // Qualifiable + #[serde(skip_serializing_if = "Vec::is_empty")] + pub qualifiers: Vec, +} + +impl ReferenceElement { + pub fn new(id_short: String, value: Option) -> Self { + Self { + id_short, + value, + semantic_id: None, + embedded_data_specification: vec![], + model_type: ModelType::new(ModelTypeName::ReferenceElement), + kind: None, + category: None, + qualifiers: vec![], + } + } +} diff --git a/src/submodel_element/submodel_element_collection.rs b/src/submodel_element/submodel_element_collection.rs new file mode 100644 index 0000000..33b22fa --- /dev/null +++ b/src/submodel_element/submodel_element_collection.rs @@ -0,0 +1,65 @@ +use super::{EmbeddedDataSpecification, Qualifier, SubmodelElement}; +use crate::{ + category::Category, + model_type::{ModelType, ModelTypeName}, + modeling_kind::ModelingKind, + reference::Reference, +}; +use serde::{Deserialize, Serialize}; + +#[derive(Serialize, Deserialize, Debug, Clone)] +#[serde(rename_all = "camelCase")] +pub struct SubmodelElementCollection { + // SubmodelElementCollection + pub ordered: bool, + pub allow_duplicates: bool, + #[serde(skip_serializing_if = "Vec::is_empty")] + pub value: Vec, + + // SubmodelElement + pub id_short: String, + #[serde(skip_serializing_if = "Option::is_none")] + pub kind: Option, + + // Referable + pub model_type: ModelType, + #[serde(skip_serializing_if = "Option::is_none")] + pub category: Option, + + // HasDataSpecification + #[serde(skip_serializing_if = "Vec::is_empty")] + pub embedded_data_specification: Vec, + + // HasSemantics + #[serde(skip_serializing_if = "Option::is_none")] + pub semantic_id: Option, + + // Qualifiable + #[serde(skip_serializing_if = "Vec::is_empty")] + pub qualifiers: Vec, +} + +impl SubmodelElementCollection { + pub fn new( + id_short: String, + ordered: bool, + allow_duplicates: bool, + submodel_elements: Vec, + ) -> Self { + Self { + id_short, + ordered, + allow_duplicates, + value: submodel_elements, + semantic_id: None, + embedded_data_specification: vec![], + category: None, + qualifiers: vec![], + model_type: ModelType::new(ModelTypeName::SubmodelElementCollection), + kind: None, + } + } + pub fn add_submodel_element(&mut self, element: SubmodelElement) { + self.value.push(element); + } +} diff --git a/src/submodel_element/value_type.rs b/src/submodel_element/value_type.rs new file mode 100644 index 0000000..6aa0289 --- /dev/null +++ b/src/submodel_element/value_type.rs @@ -0,0 +1,17 @@ +use super::data_object_type::DataObjectType; +use crate::DataObjectTypeName; +use serde::{Deserialize, Serialize}; + +#[derive(Serialize, Deserialize, Debug, Clone)] +#[serde(rename_all = "camelCase")] +pub struct ValueType { + pub data_object_type: DataObjectType, +} + +impl ValueType { + pub fn new(type_name: DataObjectTypeName) -> Self { + Self { + data_object_type: DataObjectType { name: type_name }, + } + } +} diff --git a/src/submodel_element/variable.rs b/src/submodel_element/variable.rs new file mode 100644 index 0000000..82451cc --- /dev/null +++ b/src/submodel_element/variable.rs @@ -0,0 +1,20 @@ +use super::OperationVariable; +use super::SubmodelElement; +use crate::model_type::{ModelType, ModelTypeName}; +use serde::{Deserialize, Serialize}; + +#[derive(Serialize, Deserialize, Debug, Clone)] +#[serde(rename_all = "camelCase")] +pub struct Variable { + pub value: OperationVariable, + pub model_type: ModelType, +} + +impl Variable { + pub fn new(submodel_element: SubmodelElement) -> Self { + Self { + value: OperationVariable { submodel_element }, + model_type: ModelType::new(ModelTypeName::OperationVariable), + } + } +} diff --git a/src/value.rs b/src/value.rs new file mode 100644 index 0000000..337fbcd --- /dev/null +++ b/src/value.rs @@ -0,0 +1,42 @@ +use crate::{error::AASError, DataObjectTypeName}; +use serde::{Deserialize, Serialize}; + +#[derive(Serialize, Deserialize, Debug, Clone)] +#[serde(untagged)] +pub enum Value { + Int(i32), + String(String), + Boolean(bool), + Double(f64), +} + +impl Value { + pub fn new(value_type: DataObjectTypeName, value: String) -> Result, AASError> { + if value == "null" { + Ok(None) + } else { + let value = match value_type { + DataObjectTypeName::Int => Some(Value::Int(value.parse::()?)), + DataObjectTypeName::Double => Some(Value::Double(value.parse::()?)), + DataObjectTypeName::Float => Some(Value::Double(value.parse::()?)), + DataObjectTypeName::String => Some(Value::String(value)), + DataObjectTypeName::Short => Some(Value::Int(value.parse::()?)), + DataObjectTypeName::Boolean => Some(Value::Boolean(value.parse::()?)), + DataObjectTypeName::Byte => Some(Value::Int(value.parse::()?)), + _ => return Err(AASError::UnsupportedType(value_type)), + }; + Ok(value) + } + } +} + +impl ToString for Value { + fn to_string(&self) -> std::string::String { + match &self { + Value::Int(a) => format!("{}", a), + Value::String(a) => a.clone(), + Value::Boolean(a) => format!("{}", a), + Value::Double(a) => format!("{}", a), + } + } +}