diff --git a/Cargo.lock b/Cargo.lock index c492fdd..288c339 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,279 +2,18 @@ # It is not intended for manual editing. version = 4 -[[package]] -name = "actix" -version = "0.13.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "de7fa236829ba0841304542f7614c42b80fca007455315c45c785ccfa873a85b" -dependencies = [ - "actix-macros", - "actix-rt", - "actix_derive", - "bitflags", - "bytes", - "crossbeam-channel", - "futures-core", - "futures-sink", - "futures-task", - "futures-util", - "log", - "once_cell", - "parking_lot", - "pin-project-lite", - "smallvec", - "tokio", - "tokio-util", -] - -[[package]] -name = "actix-macros" -version = "0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e01ed3140b2f8d422c68afa1ed2e85d996ea619c988ac834d255db32138655cb" -dependencies = [ - "quote", - "syn", -] - -[[package]] -name = "actix-rt" -version = "2.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24eda4e2a6e042aa4e55ac438a2ae052d3b5da0ecf83d7411e1a368946925208" -dependencies = [ - "futures-core", - "tokio", -] - -[[package]] -name = "actix_derive" -version = "0.6.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6ac1e58cded18cb28ddc17143c4dea5345b3ad575e14f32f66e4054a56eb271" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "addr2line" -version = "0.24.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dfbe277e56a376000877090da837660b4427aad530e3028d44e0bffe4f89a1c1" -dependencies = [ - "gimli", -] - -[[package]] -name = "adler2" -version = "2.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa" - -[[package]] -name = "aho-corasick" -version = "1.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" -dependencies = [ - "memchr", -] - -[[package]] -name = "autocfg" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" - -[[package]] -name = "backtrace" -version = "0.3.75" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6806a6321ec58106fea15becdad98371e28d92ccbc7c8f1b3b6dd724fe8f1002" -dependencies = [ - "addr2line", - "cfg-if", - "libc", - "miniz_oxide", - "object", - "rustc-demangle", - "windows-targets 0.52.6", -] - -[[package]] -name = "bitflags" -version = "2.9.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b8e56985ec62d17e9c1001dc89c88ecd7dc08e47eba5ec7c29c7b5eeecde967" - -[[package]] -name = "bstr" -version = "1.12.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "234113d19d0d7d613b40e86fb654acf958910802bcceab913a4f9e7cda03b1a4" -dependencies = [ - "memchr", - "serde", -] - -[[package]] -name = "bytes" -version = "1.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d71b6127be86fdcfddb610f7182ac57211d4b18a3e9c82eb2d17662f2227ad6a" - -[[package]] -name = "cfg-if" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9555578bc9e57714c812a1f84e4fc5b4d21fcb063490c624de019f7464c91268" - -[[package]] -name = "crossbeam-channel" -version = "0.5.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "82b8f8f868b36967f9606790d1903570de9ceaf870a7bf9fbbd3016d636a2cb2" -dependencies = [ - "crossbeam-utils", -] - -[[package]] -name = "crossbeam-utils" -version = "0.8.21" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" - -[[package]] -name = "futures-core" -version = "0.3.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" - -[[package]] -name = "futures-sink" -version = "0.3.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e575fab7d1e0dcb8d0c7bcf9a63ee213816ab51902e6d244a95819acacf1d4f7" - -[[package]] -name = "futures-task" -version = "0.3.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988" - -[[package]] -name = "futures-util" -version = "0.3.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81" -dependencies = [ - "futures-core", - "futures-task", - "pin-project-lite", - "pin-utils", -] - -[[package]] -name = "gimli" -version = "0.31.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f" - -[[package]] -name = "globset" -version = "0.4.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "54a1028dfc5f5df5da8a56a73e6c153c9a9708ec57232470703592a3f18e49f5" -dependencies = [ - "aho-corasick", - "bstr", - "log", - "regex-automata", - "regex-syntax", -] - -[[package]] -name = "io-uring" -version = "0.7.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b86e202f00093dcba4275d4636b93ef9dd75d025ae560d2521b45ea28ab49013" -dependencies = [ - "bitflags", - "cfg-if", - "libc", -] - [[package]] name = "itoa" version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" -[[package]] -name = "libc" -version = "0.2.174" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1171693293099992e19cddea4e8b849964e9846f4acee11b3948bcc337be8776" - -[[package]] -name = "lock_api" -version = "0.4.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96936507f153605bddfcda068dd804796c84324ed2510809e5b2a624c81da765" -dependencies = [ - "autocfg", - "scopeguard", -] - -[[package]] -name = "log" -version = "0.4.27" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94" - [[package]] name = "memchr" version = "2.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "32a282da65faaf38286cf3be983213fcf1d2e2a58700e808f83f4ea9a4804bc0" -[[package]] -name = "miniz_oxide" -version = "0.8.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316" -dependencies = [ - "adler2", -] - -[[package]] -name = "mio" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78bed444cc8a2160f01cbcf811ef18cac863ad68ae8ca62092e8db51d51c761c" -dependencies = [ - "libc", - "wasi", - "windows-sys 0.59.0", -] - -[[package]] -name = "object" -version = "0.36.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62948e14d923ea95ea2c7c86c71013138b66525b86bdc08d2dcc262bdb497b87" -dependencies = [ - "memchr", -] - -[[package]] -name = "once_cell" -version = "1.21.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" - [[package]] name = "opc_ae_bindings" version = "0.3.0" @@ -282,7 +21,6 @@ dependencies = [ "windows", "windows-bindgen", "windows-core", - "windows-targets 0.53.2", ] [[package]] @@ -300,19 +38,16 @@ dependencies = [ "windows", "windows-bindgen", "windows-core", - "windows-targets 0.53.2", ] [[package]] name = "opc_da" version = "0.3.1" dependencies = [ - "actix", - "globset", "opc_classic_utils", "opc_comn_bindings", "opc_da_bindings", - "tokio", + "thiserror", "windows", "windows-core", ] @@ -324,7 +59,6 @@ dependencies = [ "windows", "windows-bindgen", "windows-core", - "windows-targets 0.53.2", ] [[package]] @@ -334,44 +68,8 @@ dependencies = [ "windows", "windows-bindgen", "windows-core", - "windows-targets 0.53.2", ] -[[package]] -name = "parking_lot" -version = "0.12.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70d58bf43669b5795d1576d0641cfb6fbb2057bf629506267a92807158584a13" -dependencies = [ - "lock_api", - "parking_lot_core", -] - -[[package]] -name = "parking_lot_core" -version = "0.9.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc838d2a56b5b1a6c25f55575dfc605fabb63bb2365f6c2353ef9159aa69e4a5" -dependencies = [ - "cfg-if", - "libc", - "redox_syscall", - "smallvec", - "windows-targets 0.52.6", -] - -[[package]] -name = "pin-project-lite" -version = "0.2.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b" - -[[package]] -name = "pin-utils" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" - [[package]] name = "proc-macro2" version = "1.0.95" @@ -390,50 +88,12 @@ dependencies = [ "proc-macro2", ] -[[package]] -name = "redox_syscall" -version = "0.5.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d04b7d0ee6b4a0207a0a7adb104d23ecb0b47d6beae7152d0fa34b692b29fd6" -dependencies = [ - "bitflags", -] - -[[package]] -name = "regex-automata" -version = "0.4.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908" -dependencies = [ - "aho-corasick", - "memchr", - "regex-syntax", -] - -[[package]] -name = "regex-syntax" -version = "0.8.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" - -[[package]] -name = "rustc-demangle" -version = "0.1.25" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "989e6739f80c4ad5b13e0fd7fe89531180375b18520cc8c82080e4dc4035b84f" - [[package]] name = "ryu" version = "1.0.20" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f" -[[package]] -name = "scopeguard" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" - [[package]] name = "serde" version = "1.0.219" @@ -456,9 +116,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.140" +version = "1.0.141" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "20068b6e96dc6c9bd23e01df8827e6c7e1f2fddd43c21810382803c136b99373" +checksum = "30b9eff21ebe718216c6ec64e1d9ac57087aad11efc64e32002bce4a0d4c03d3" dependencies = [ "itoa", "memchr", @@ -466,37 +126,6 @@ dependencies = [ "serde", ] -[[package]] -name = "signal-hook-registry" -version = "1.4.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9203b8055f63a2a00e2f593bb0510367fe707d7ff1e5c872de2f537b339e5410" -dependencies = [ - "libc", -] - -[[package]] -name = "slab" -version = "0.4.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04dc19736151f35336d325007ac991178d504a119863a2fcb3758cdb5e52c50d" - -[[package]] -name = "smallvec" -version = "1.15.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" - -[[package]] -name = "socket2" -version = "0.5.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e22376abed350d73dd1cd119b57ffccad95b4e585a7cda43e286245ce23c0678" -dependencies = [ - "libc", - "windows-sys 0.52.0", -] - [[package]] name = "syn" version = "2.0.104" @@ -509,61 +138,31 @@ dependencies = [ ] [[package]] -name = "tokio" -version = "1.46.1" +name = "thiserror" +version = "2.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0cc3a2344dafbe23a245241fe8b09735b521110d30fcefbbd5feb1797ca35d17" +checksum = "567b8a2dae586314f7be2a752ec7474332959c6460e02bde30d702a66d488708" dependencies = [ - "backtrace", - "bytes", - "io-uring", - "libc", - "mio", - "parking_lot", - "pin-project-lite", - "signal-hook-registry", - "slab", - "socket2", - "tokio-macros", - "windows-sys 0.52.0", + "thiserror-impl", ] [[package]] -name = "tokio-macros" -version = "2.5.0" +name = "thiserror-impl" +version = "2.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e06d43f1345a3bcd39f6a56dbb7dcab2ba47e68e8ac134855e7e2bdbaf8cab8" +checksum = "7f7cf42b4507d8ea322120659672cf1b9dbb93f8f2d4ecfd6e51350ff5b17a1d" dependencies = [ "proc-macro2", "quote", "syn", ] -[[package]] -name = "tokio-util" -version = "0.7.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "66a539a9ad6d5d281510d5bd368c973d636c02dbf8a67300bfb6b950696ad7df" -dependencies = [ - "bytes", - "futures-core", - "futures-sink", - "pin-project-lite", - "tokio", -] - [[package]] name = "unicode-ident" version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512" -[[package]] -name = "wasi" -version = "0.11.1+wasi-snapshot-preview1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" - [[package]] name = "windows" version = "0.61.3" @@ -677,56 +276,6 @@ dependencies = [ "windows-link", ] -[[package]] -name = "windows-sys" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" -dependencies = [ - "windows-targets 0.52.6", -] - -[[package]] -name = "windows-sys" -version = "0.59.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" -dependencies = [ - "windows-targets 0.52.6", -] - -[[package]] -name = "windows-targets" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" -dependencies = [ - "windows_aarch64_gnullvm 0.52.6", - "windows_aarch64_msvc 0.52.6", - "windows_i686_gnu 0.52.6", - "windows_i686_gnullvm 0.52.6", - "windows_i686_msvc 0.52.6", - "windows_x86_64_gnu 0.52.6", - "windows_x86_64_gnullvm 0.52.6", - "windows_x86_64_msvc 0.52.6", -] - -[[package]] -name = "windows-targets" -version = "0.53.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c66f69fcc9ce11da9966ddb31a40968cad001c5bedeb5c2b82ede4253ab48aef" -dependencies = [ - "windows_aarch64_gnullvm 0.53.0", - "windows_aarch64_msvc 0.53.0", - "windows_i686_gnu 0.53.0", - "windows_i686_gnullvm 0.53.0", - "windows_i686_msvc 0.53.0", - "windows_x86_64_gnu 0.53.0", - "windows_x86_64_gnullvm 0.53.0", - "windows_x86_64_msvc 0.53.0", -] - [[package]] name = "windows-threading" version = "0.1.0" @@ -735,99 +284,3 @@ checksum = "b66463ad2e0ea3bbf808b7f1d371311c80e115c0b71d60efc142cafbcfb057a6" dependencies = [ "windows-link", ] - -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" - -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.53.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86b8d5f90ddd19cb4a147a5fa63ca848db3df085e25fee3cc10b39b6eebae764" - -[[package]] -name = "windows_aarch64_msvc" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" - -[[package]] -name = "windows_aarch64_msvc" -version = "0.53.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7651a1f62a11b8cbd5e0d42526e55f2c99886c77e007179efff86c2b137e66c" - -[[package]] -name = "windows_i686_gnu" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" - -[[package]] -name = "windows_i686_gnu" -version = "0.53.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1dc67659d35f387f5f6c479dc4e28f1d4bb90ddd1a5d3da2e5d97b42d6272c3" - -[[package]] -name = "windows_i686_gnullvm" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" - -[[package]] -name = "windows_i686_gnullvm" -version = "0.53.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ce6ccbdedbf6d6354471319e781c0dfef054c81fbc7cf83f338a4296c0cae11" - -[[package]] -name = "windows_i686_msvc" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" - -[[package]] -name = "windows_i686_msvc" -version = "0.53.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "581fee95406bb13382d2f65cd4a908ca7b1e4c2f1917f143ba16efe98a589b5d" - -[[package]] -name = "windows_x86_64_gnu" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" - -[[package]] -name = "windows_x86_64_gnu" -version = "0.53.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2e55b5ac9ea33f2fc1716d1742db15574fd6fc8dadc51caab1c16a3d3b4190ba" - -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" - -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.53.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0a6e035dd0599267ce1ee132e51c27dd29437f63325753051e71dd9e42406c57" - -[[package]] -name = "windows_x86_64_msvc" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" - -[[package]] -name = "windows_x86_64_msvc" -version = "0.53.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "271414315aff87387382ec3d271b52d7ae78726f5d44ac98b4f4030c91880486" diff --git a/Cargo.toml b/Cargo.toml index 9214aaa..7889214 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,12 +10,11 @@ members = [ ] [workspace.dependencies] -actix = "0.13.5" -globset = "0.4.16" -opc_classic_utils = { version = "0.3.0", path = "opc_classic_utils" } +opc_classic_utils = { path = "opc_classic_utils" } opc_comn_bindings = { path = "opc_comn_bindings" } opc_da_bindings = { path = "opc_da_bindings" } -tokio = { version = "1.46.1", features = ["full"] } +opc_hda_bindings = { path = "opc_hda_bindings" } +thiserror = "2.0" windows = { version = "0.61.3", features = [ "Win32_Foundation", "Win32_Graphics_Gdi", @@ -27,7 +26,6 @@ windows = { version = "0.61.3", features = [ ] } windows-bindgen = "0.62.1" windows-core = "0.61.2" -windows-targets = "0.53.2" [profile.dev.build-override] debug = true diff --git a/opc_ae_bindings/Cargo.toml b/opc_ae_bindings/Cargo.toml index c8dbda7..8c753eb 100644 --- a/opc_ae_bindings/Cargo.toml +++ b/opc_ae_bindings/Cargo.toml @@ -16,7 +16,6 @@ targets = [] [dependencies] windows = { workspace = true } windows-core = { workspace = true } -windows-targets = { workspace = true } [build-dependencies] windows-bindgen = { workspace = true } diff --git a/opc_ae_bindings/build.rs b/opc_ae_bindings/build.rs index 19d638c..c2a53ae 100644 --- a/opc_ae_bindings/build.rs +++ b/opc_ae_bindings/build.rs @@ -13,7 +13,6 @@ fn main() { "--filter", "OPCAE", "--flat", - "--implement", ]) .unwrap(); } diff --git a/opc_comn_bindings/Cargo.toml b/opc_comn_bindings/Cargo.toml index 966673e..5b4206e 100644 --- a/opc_comn_bindings/Cargo.toml +++ b/opc_comn_bindings/Cargo.toml @@ -16,7 +16,6 @@ targets = [] [dependencies] windows = { workspace = true } windows-core = { workspace = true } -windows-targets = { workspace = true } [build-dependencies] windows-bindgen = { workspace = true } diff --git a/opc_comn_bindings/build.rs b/opc_comn_bindings/build.rs index 2c9cbd4..47fff18 100644 --- a/opc_comn_bindings/build.rs +++ b/opc_comn_bindings/build.rs @@ -13,7 +13,6 @@ fn main() { "--filter", "OPCCOMN", "--flat", - "--implement", ]) .unwrap(); } diff --git a/opc_da/Cargo.toml b/opc_da/Cargo.toml index c2de177..b8b9a87 100644 --- a/opc_da/Cargo.toml +++ b/opc_da/Cargo.toml @@ -12,16 +12,9 @@ default-target = "x86_64-pc-windows-msvc" targets = [] [dependencies] -actix = { workspace = true } -globset = { workspace = true } opc_classic_utils = { workspace = true } opc_comn_bindings = { workspace = true } opc_da_bindings = { workspace = true } -tokio = { workspace = true } +thiserror = { workspace = true } windows = { workspace = true } windows-core = { workspace = true } - -[features] -default = ["unstable_client", "unstable_server"] -unstable_client = [] -unstable_server = [] diff --git a/opc_da/src/client/iterator.rs b/opc_da/src/client/iterator.rs deleted file mode 100644 index e57a2ec..0000000 --- a/opc_da/src/client/iterator.rs +++ /dev/null @@ -1,250 +0,0 @@ -use crate::{ - def::ItemAttributes, - utils::{RemoteArray, RemotePointer, TryToLocal as _}, -}; - -const MAX_CACHE_SIZE: usize = 16; - -/// Iterator over COM GUIDs from IEnumGUID. -/// -/// # Safety -/// This struct wraps a COM interface and must be used according to COM rules. -pub struct GuidIterator { - inner: windows::Win32::System::Com::IEnumGUID, - cache: Box<[windows::core::GUID; MAX_CACHE_SIZE]>, - index: u32, - count: u32, - done: bool, -} - -impl GuidIterator { - /// Creates a new iterator from a COM interface. - pub fn new(inner: windows::Win32::System::Com::IEnumGUID) -> Self { - Self { - inner, - cache: Box::from([windows::core::GUID::zeroed(); MAX_CACHE_SIZE]), - index: 0, - count: 0, - done: false, - } - } -} - -impl Iterator for GuidIterator { - type Item = windows::core::Result; - - fn next(&mut self) -> Option { - if self.done { - return None; - } - - if self.index == self.cache.len() as u32 { - let code = unsafe { - self.inner - .Next(self.cache.as_mut_slice(), Some(&mut self.count)) - }; - - if code.is_ok() { - if self.count == 0 { - self.done = true; - return None; - } - - self.index = 0; - } else { - self.done = true; - return Some(Err(windows::core::Error::new( - code, - "Failed to get next GUID", - ))); - } - } - - let current = self.cache[self.index as usize]; - self.index += 1; - Some(Ok(current)) - } -} - -pub struct StringIterator { - inner: windows::Win32::System::Com::IEnumString, - cache: Box<[windows::core::PWSTR; MAX_CACHE_SIZE]>, - index: u32, - count: u32, - done: bool, -} - -impl StringIterator { - pub fn new(inner: windows::Win32::System::Com::IEnumString) -> Self { - Self { - inner, - cache: Box::new([windows::core::PWSTR::null(); MAX_CACHE_SIZE]), - index: 0, - count: 0, - done: false, - } - } -} - -impl Iterator for StringIterator { - type Item = windows::core::Result; - - fn next(&mut self) -> Option { - if self.done { - return None; - } - - if self.index == self.cache.len() as u32 { - let code = unsafe { - self.inner - .Next(self.cache.as_mut_slice(), Some(&mut self.count)) - }; - - if code.is_ok() { - if self.count == 0 { - self.done = true; - return None; - } - - self.index = 0; - } else { - self.done = true; - return Some(Err(windows::core::Error::new( - code, - "Failed to get next string", - ))); - } - } - - let current = RemotePointer::from(self.cache[self.index as usize]); - self.index += 1; - Some(current.try_into()) - } -} - -pub struct GroupIterator> { - inner: windows::Win32::System::Com::IEnumUnknown, - cache: Box<[Option; MAX_CACHE_SIZE]>, - index: u32, - count: u32, - done: bool, - _mark: std::marker::PhantomData, -} - -impl> GroupIterator { - pub fn new(inner: windows::Win32::System::Com::IEnumUnknown) -> Self { - Self { - inner, - cache: Box::from([const { None }; MAX_CACHE_SIZE]), - index: 0, - count: 0, - done: false, - _mark: std::marker::PhantomData, - } - } -} - -impl> Iterator - for GroupIterator -{ - type Item = windows::core::Result; - - fn next(&mut self) -> Option { - if self.done { - return None; - } - - if self.index == self.cache.len() as u32 { - let code = unsafe { - self.inner - .Next(self.cache.as_mut_slice(), Some(&mut self.count)) - }; - - if code.is_ok() { - if self.count == 0 { - self.done = true; - return None; - } - - self.index = 0; - } else { - self.done = true; - return Some(Err(windows::core::Error::new( - code, - "Failed to get next group", - ))); - } - } - - let current = self.cache[self.index as usize].take(); - self.index += 1; - Some(match current { - Some(group) => group.try_into(), - None => Err(windows::core::Error::new( - windows::Win32::Foundation::E_POINTER, - "Failed to get group, returned null", - )), - }) - } -} - -// for opc_da_bindings::IEnumOPCItemAttributes -pub struct ItemAttributeIterator { - inner: opc_da_bindings::IEnumOPCItemAttributes, - cache: RemoteArray, - index: u32, - done: bool, -} - -impl ItemAttributeIterator { - pub fn new(inner: opc_da_bindings::IEnumOPCItemAttributes) -> Self { - Self { - inner, - cache: RemoteArray::empty(), - index: 0, - done: false, - } - } -} - -impl Iterator for ItemAttributeIterator { - type Item = windows::core::Result; - - fn next(&mut self) -> Option { - if self.done { - return None; - } - - if self.index == self.cache.len() { - let mut attrs = RemoteArray::new(MAX_CACHE_SIZE as u32); - - let result = unsafe { - self.inner.Next( - MAX_CACHE_SIZE as u32, - attrs.as_mut_ptr(), - attrs.as_mut_len_ptr(), - ) - }; - - match result { - Ok(_) => { - if attrs.is_empty() { - self.done = true; - return None; - } - - self.cache = attrs; - self.index = 0; - } - Err(err) => { - self.done = true; - return Some(Err(err)); - } - } - } - - let current = self.cache.as_slice()[self.index as usize].try_to_local(); - self.index += 1; - Some(current) - } -} diff --git a/opc_da/src/client/mod.rs b/opc_da/src/client/mod.rs deleted file mode 100644 index 976b32a..0000000 --- a/opc_da/src/client/mod.rs +++ /dev/null @@ -1,22 +0,0 @@ -//! OPC DA client implementation. -//! -//! This module provides implementations for OPC DA client functionality across -//! different versions of the specification (1.0, 2.0, and 3.0). It includes: -//! -//! - Version-specific implementations in `v1`, `v2`, and `v3` modules -//! - A unified client interface in the `unified` module -//! - Common traits and memory management utilities - -mod iterator; -mod traits; - -pub mod unified; -pub mod v1; -pub mod v2; -pub mod v3; - -pub use iterator::*; -pub use traits::*; - -#[cfg(test)] -mod tests; diff --git a/opc_da/src/client/tests.rs b/opc_da/src/client/tests.rs deleted file mode 100644 index db4c482..0000000 --- a/opc_da/src/client/tests.rs +++ /dev/null @@ -1,134 +0,0 @@ -use unified::{Guard, Server}; - -use crate::utils::LocalPointer; - -use super::*; - -#[test] -fn test_client() { - let client = Guard::new(unified::Client::v2()).expect("Failed to create guard"); - - let servers = client - .get_servers() - .expect("Failed to get servers") - .collect::>(); - - if servers.is_empty() { - panic!("No servers found"); - } - - let server_id = servers - .first() - .cloned() - .expect("No server found") - .expect("Failed to get server id"); - - println!("Server ID: {:?}", server_id); - - let server = client - .create_server(server_id) - .expect("Failed to create server"); - - let server = match server { - Server::V2(server) => server, - _ => panic!("Expected V2 server"), - }; - - let branch = StringIterator::new( - server - .browse_opc_item_ids(opc_da_bindings::OPC_BRANCH, Some(""), 0, 0) - .expect("Failed to browse items"), - ) - .take(1) - .collect::, _>>() - .expect("No names found") - .pop() - .expect("No branch found"); - - println!("Branch: {:?}", branch); - - server - .change_browse_position(opc_da_bindings::OPC_BROWSE_TO, &branch) - .expect("Failed to change browse position"); - - let leaf = StringIterator::new( - server - .browse_opc_item_ids(opc_da_bindings::OPC_FLAT, Some(""), 0, 0) - .expect("Failed to browse items"), - ) - .take(1) - .collect::, _>>() - .expect("No names found") - .pop() - .expect("No leaf found"); - - println!("Leaf: {:?}", leaf); - - let name = server.get_item_id(&leaf).expect("Failed to get item id"); - - println!("Item name: {:?}", name); - - let mut group_server_handle = 0u32; - let mut revised_percent_deadband = 0u32; - let group = server - .add_group( - "test", - true, - 0, - 0, - 0, - 0, - 0.0, - &mut revised_percent_deadband, - &mut group_server_handle, - ) - .expect("Failed to add group"); - - let name = LocalPointer::from(&name); - let (results, errors) = group - .add_items(&[opc_da_bindings::tagOPCITEMDEF { - szAccessPath: windows::core::PWSTR::null(), - szItemID: name.as_pwstr(), - bActive: true.into(), - hClient: 0, - dwBlobSize: 0, - pBlob: std::ptr::null_mut(), - vtRequestedDataType: 0, - wReserved: 0, - }]) - .expect("Failed to add items"); - - assert_eq!(errors.len(), 1, "Expected exactly one error result"); - let error = errors.as_slice().first().expect("Error array is empty"); - assert!(error.is_ok(), "Unexpected error: {:?}", error); - - assert_eq!(results.len(), 1, "Expected exactly one result"); - let server_handle = results - .as_slice() - .first() - .unwrap_or_else(|| panic!("Expected 1 result, got {}", results.len())) - .hServer; - - let (states, errors) = - SyncIoTrait::read(&group, opc_da_bindings::OPC_DS_CACHE, &[server_handle]) - .expect("Failed to read"); - - if errors.len() != 1 { - panic!("Expected 1 error, got {}", errors.len()); - } - - let error = errors.as_slice().first().unwrap(); - if error.is_err() { - panic!("Error, got {:?}", error); - } - - if states.len() != 1 { - panic!("Expected 1 state, got {}", states.len()); - } - - let state = states.as_slice().first().unwrap(); - println!("State: {:?}", state.vDataValue); - - let cloned_value = state.vDataValue.clone(); - SyncIoTrait::write(&group, &[server_handle], &[cloned_value]).expect("Failed to write"); -} diff --git a/opc_da/src/client/traits/async_io.rs b/opc_da/src/client/traits/async_io.rs deleted file mode 100644 index bec975f..0000000 --- a/opc_da/src/client/traits/async_io.rs +++ /dev/null @@ -1,135 +0,0 @@ -use windows::Win32::System::Variant::VARIANT; - -use crate::utils::RemoteArray; - -/// Asynchronous I/O functionality (OPC DA 1.0). -/// -/// Provides basic asynchronous read/write operations using connection point callbacks. -/// This is the original asynchronous interface defined in OPC DA 1.0. -pub trait AsyncIoTrait { - fn interface(&self) -> windows::core::Result<&opc_da_bindings::IOPCAsyncIO>; - - /// Reads values asynchronously from the server. - /// - /// # Arguments - /// * `connection` - Connection point cookie for receiving callbacks - /// * `source` - Specifies whether to read from cache or device - /// * `server_handles` - Array of server item handles to read - /// - /// # Returns - /// * `transaction_id` - Identifies this operation in callbacks - /// * `errors` - Array of per-item error codes - /// - /// # Errors - /// Returns E_INVALIDARG if server_handles is empty - fn read( - &self, - connection: u32, - source: opc_da_bindings::tagOPCDATASOURCE, - server_handles: &[u32], - ) -> windows::core::Result<(u32, RemoteArray)> { - if server_handles.is_empty() { - return Err(windows::core::Error::new( - windows::Win32::Foundation::E_INVALIDARG, - "server_handles cannot be empty", - )); - } - - let len = server_handles.len().try_into()?; - - let mut transaction_id = 0; - let mut errors = RemoteArray::new(len); - - unsafe { - self.interface()?.Read( - connection, - source, - len, - server_handles.as_ptr(), - &mut transaction_id, - errors.as_mut_ptr(), - )?; - } - - Ok((transaction_id, errors)) - } - - /// Writes values asynchronously to the server. - /// - /// # Arguments - /// * `connection` - Connection point cookie for receiving callbacks - /// * `server_handles` - Array of server item handles to write - /// * `values` - Array of values to write - /// - /// # Returns - /// * `transaction_id` - Identifies this operation in callbacks - /// * `errors` - Array of per-item error codes - /// - /// # Errors - /// Returns E_INVALIDARG if arrays are empty or have different lengths - fn write( - &self, - connection: u32, - server_handles: &[u32], - values: &[VARIANT], - ) -> windows::core::Result<(u32, RemoteArray)> { - if server_handles.len() != values.len() { - return Err(windows::core::Error::new( - windows::Win32::Foundation::E_INVALIDARG, - "server_handles and values must have the same length", - )); - } - - if server_handles.is_empty() { - return Err(windows::core::Error::new( - windows::Win32::Foundation::E_INVALIDARG, - "server_handles cannot be empty", - )); - } - - let len = server_handles.len().try_into()?; - - let mut transaction_id = 0; - let mut errors = RemoteArray::new(len); - - unsafe { - self.interface()?.Write( - connection, - len, - server_handles.as_ptr(), - values.as_ptr(), - &mut transaction_id, - errors.as_mut_ptr(), - )?; - } - - Ok((transaction_id, errors)) - } - - /// Refreshes all active items asynchronously. - /// - /// # Arguments - /// * `connection` - Connection point cookie for receiving callbacks - /// * `source` - Specifies whether to refresh from cache or device - /// - /// # Returns - /// Transaction ID for identifying the operation in callbacks - fn refresh( - &self, - connection: u32, - source: opc_da_bindings::tagOPCDATASOURCE, - ) -> windows::core::Result { - unsafe { self.interface()?.Refresh(connection, source) } - } - - /// Cancels an outstanding asynchronous operation. - /// - /// # Arguments - /// * `transaction_id` - ID of the operation to cancel - /// - /// # Returns - /// Result indicating success or failure of cancel request - fn cancel(&self, transaction_id: u32) -> windows::core::Result<()> { - unsafe { self.interface()?.Cancel(transaction_id) } - } -} diff --git a/opc_da/src/client/traits/async_io2.rs b/opc_da/src/client/traits/async_io2.rs deleted file mode 100644 index 1909a4b..0000000 --- a/opc_da/src/client/traits/async_io2.rs +++ /dev/null @@ -1,125 +0,0 @@ -use crate::utils::RemoteArray; - -/// Asynchronous I/O functionality (OPC DA 2.0). -/// -/// Provides enhanced asynchronous read/write operations without requiring -/// connection point callbacks. This trait extends the functionality of -/// AsyncIoTrait with improved error handling and control mechanisms. -pub trait AsyncIo2Trait { - fn interface(&self) -> windows::core::Result<&opc_da_bindings::IOPCAsyncIO2>; - - /// Initiates an asynchronous read operation. - /// - /// # Arguments - /// * `server_handles` - Array of server item handles to read - /// * `transaction_id` - Client-provided transaction identifier - /// - /// # Returns - /// Tuple containing (cancel_id, error_array) where: - /// - cancel_id: Identifier used to cancel the operation - /// - error_array: Array of HRESULT values indicating per-item status - fn read( - &self, - server_handles: &[u32], - transaction_id: u32, - ) -> windows::core::Result<(u32, RemoteArray)> { - let len = server_handles.len().try_into()?; - - let mut cancel_id = 0; - let mut errors = RemoteArray::new(len); - - unsafe { - self.interface()?.Read( - len, - server_handles.as_ptr(), - transaction_id, - &mut cancel_id, - errors.as_mut_ptr(), - )?; - } - - Ok((cancel_id, errors)) - } - - /// Initiates an asynchronous write operation. - /// - /// # Arguments - /// * `server_handles` - Array of server item handles to write - /// * `values` - Array of VARIANT values to write - /// * `transaction_id` - Client-provided transaction identifier - /// - /// # Returns - /// Tuple containing (cancel_id, error_array) where: - /// - cancel_id: Identifier used to cancel the operation - /// - error_array: Array of HRESULT values indicating per-item status - fn write( - &self, - server_handles: &[u32], - values: &[windows::Win32::System::Variant::VARIANT], - transaction_id: u32, - ) -> windows::core::Result<(u32, RemoteArray)> { - let len = server_handles.len().try_into()?; - - let mut cancel_id = 0; - let mut errors = RemoteArray::new(len); - - unsafe { - self.interface()?.Write( - len, - server_handles.as_ptr(), - values.as_ptr(), - transaction_id, - &mut cancel_id, - errors.as_mut_ptr(), - )?; - } - - Ok((cancel_id, errors)) - } - - /// Refreshes all active items from the specified source. - /// - /// # Arguments - /// * `source` - Data source (cache or device) - /// * `transaction_id` - Client-provided transaction identifier - /// - /// # Returns - /// Cancel ID that can be used to cancel the operation - fn refresh2( - &self, - source: opc_da_bindings::tagOPCDATASOURCE, - transaction_id: u32, - ) -> windows::core::Result { - unsafe { self.interface()?.Refresh2(source, transaction_id) } - } - - /// Cancels a pending asynchronous operation. - /// - /// # Arguments - /// * `cancel_id` - Cancel ID returned from read/write operations - /// - /// # Returns - /// `Ok(())` if the operation was successfully canceled - fn cancel2(&self, cancel_id: u32) -> windows::core::Result<()> { - unsafe { self.interface()?.Cancel2(cancel_id) } - } - - /// Enables or disables asynchronous I/O operations. - /// - /// # Arguments - /// * `enable` - `true` to enable async operations, `false` to disable - /// - /// # Returns - /// `Ok(())` if the enable state was successfully changed - fn set_enable(&self, enable: bool) -> windows::core::Result<()> { - unsafe { self.interface()?.SetEnable(enable) } - } - - /// Gets the current enable state of asynchronous I/O operations. - /// - /// # Returns - /// `true` if async operations are enabled, `false` otherwise - fn get_enable(&self) -> windows::core::Result { - unsafe { self.interface()?.GetEnable().map(|v| v.as_bool()) } - } -} diff --git a/opc_da/src/client/traits/async_io3.rs b/opc_da/src/client/traits/async_io3.rs deleted file mode 100644 index fce76c3..0000000 --- a/opc_da/src/client/traits/async_io3.rs +++ /dev/null @@ -1,103 +0,0 @@ -use crate::utils::RemoteArray; - -/// Asynchronous I/O functionality (OPC DA 3.0). -/// -/// Provides methods for enhanced asynchronous read/write operations with -/// quality and timestamp information. -pub trait AsyncIo3Trait { - fn interface(&self) -> windows::core::Result<&opc_da_bindings::IOPCAsyncIO3>; - - /// Reads values with maximum age constraint. - /// - /// # Arguments - /// * `server_handles` - Array of server item handles - /// * `max_age` - Maximum age constraints for each item (milliseconds) - /// * `transaction_id` - Client-provided transaction identifier - /// - /// # Returns - /// Tuple containing cancel ID and array of per-item error codes - fn read_max_age( - &self, - server_handles: &[u32], - max_age: &[u32], - transaction_id: u32, - ) -> windows::core::Result<(u32, RemoteArray)> { - if server_handles.len() != max_age.len() { - return Err(windows::core::Error::new( - windows::Win32::Foundation::E_INVALIDARG, - "server_handles and max_age must have the same length", - )); - } - - let len = server_handles.len().try_into()?; - - let mut cancel_id = 0; - let mut errors = RemoteArray::new(len); - - unsafe { - self.interface()?.ReadMaxAge( - len, - server_handles.as_ptr(), - max_age.as_ptr(), - transaction_id, - &mut cancel_id, - errors.as_mut_ptr(), - )?; - } - - Ok((cancel_id, errors)) - } - - /// Writes values with quality and timestamp information. - /// - /// # Arguments - /// * `server_handles` - Array of server item handles - /// * `values` - Array of values with quality and timestamp (VQT) - /// * `transaction_id` - Client-provided transaction identifier - /// - /// # Returns - /// Tuple containing cancel ID and array of per-item error codes - fn write_vqt( - &self, - server_handles: &[u32], - values: &[opc_da_bindings::tagOPCITEMVQT], - transaction_id: u32, - ) -> windows::core::Result<(u32, RemoteArray)> { - if server_handles.len() != values.len() { - return Err(windows::core::Error::new( - windows::Win32::Foundation::E_INVALIDARG, - "server_handles and values must have the same length", - )); - } - - let len = server_handles.len().try_into()?; - - let mut cancel_id = 0; - let mut errors = RemoteArray::new(len); - - unsafe { - self.interface()?.WriteVQT( - len, - server_handles.as_ptr(), - values.as_ptr(), - transaction_id, - &mut cancel_id, - errors.as_mut_ptr(), - )?; - } - - Ok((cancel_id, errors)) - } - - /// Refreshes all active items with maximum age constraint. - /// - /// # Arguments - /// * `max_age` - Maximum age constraint in milliseconds - /// * `transaction_id` - Client-provided transaction identifier - /// - /// # Returns - /// Cancel ID for the refresh operation - fn refresh_max_age(&self, max_age: u32, transaction_id: u32) -> windows::core::Result { - unsafe { self.interface()?.RefreshMaxAge(max_age, transaction_id) } - } -} diff --git a/opc_da/src/client/traits/browse.rs b/opc_da/src/client/traits/browse.rs deleted file mode 100644 index a5c5326..0000000 --- a/opc_da/src/client/traits/browse.rs +++ /dev/null @@ -1,126 +0,0 @@ -use opc_da_bindings::{tagOPCBROWSEELEMENT, tagOPCBROWSEFILTER, tagOPCITEMPROPERTIES, IOPCBrowse}; - -use crate::utils::{LocalPointer, RemoteArray, RemotePointer}; - -/// Server address space browsing functionality (OPC DA 3.0). -/// -/// Provides methods to browse the hierarchical namespace of an OPC server -/// and retrieve item properties. -pub trait BrowseTrait { - fn interface(&self) -> windows::core::Result<&IOPCBrowse>; - - /// Gets properties for specified items from the server. - /// - /// # Arguments - /// * `item_ids` - Array of item identifiers to get properties for - /// * `return_property_values` - If true, return actual property values; if false, only property metadata - /// * `property_ids` - Specific property IDs to retrieve; empty array means all properties - /// - /// # Returns - /// Array of item properties containing property values and/or metadata - /// - /// # Errors - /// Returns E_INVALIDARG if item_ids is empty - fn get_properties( - &self, - item_ids: &[String], - return_property_values: bool, - property_ids: &[u32], - ) -> windows::core::Result> { - if item_ids.is_empty() { - return Err(windows::core::Error::new( - windows::Win32::Foundation::E_INVALIDARG, - "item_ids is empty", - )); - } - - let item_ptrs: LocalPointer>> = LocalPointer::from(item_ids); - let item_ptrs = item_ptrs.as_pcwstr_array(); - - let mut results = RemoteArray::new(item_ids.len().try_into()?); - - unsafe { - self.interface()?.GetProperties( - item_ids.len() as u32, - item_ptrs.as_ptr(), - return_property_values, - property_ids, - results.as_mut_ptr(), - )?; - } - - Ok(results) - } - - /// Browses a single branch or leaf in the server's address space. - /// - /// # Arguments - /// * `item_id` - Starting point for browsing (empty string for root) - /// * `max_elements` - Maximum number of elements to return - /// * `browse_filter` - Filter specifying what types of elements to return - /// * `element_name_filter` - Filter string for element names (can contain wildcards) - /// * `vendor_filter` - Vendor-specific filter string - /// * `return_all_properties` - If true, return all available properties - /// * `return_property_values` - If true, return property values; if false, only property metadata - /// * `property_ids` - Specific property IDs to retrieve when return_all_properties is false - /// - /// # Returns - /// Tuple containing: - /// - Boolean indicating if more elements are available - /// - Array of browse elements containing names and properties - #[allow(clippy::too_many_arguments)] - fn browse( - &self, - item_id: Option, - continuation_point: Option, - max_elements: u32, - browse_filter: tagOPCBROWSEFILTER, - element_name_filter: Option, - vendor_filter: Option, - return_all_properties: bool, - return_property_values: bool, - property_ids: &[u32], - ) -> windows::core::Result<(bool, Option, RemoteArray)> - where - S0: AsRef, - S1: AsRef, - S2: AsRef, - S3: AsRef, - { - let item_id = LocalPointer::from_option(item_id); - let element_name_filter = LocalPointer::from_option(element_name_filter); - let vendor_filter = LocalPointer::from_option(vendor_filter); - let mut continuation_point = - RemotePointer::from_option(continuation_point.as_ref().map(|v| v.as_ref())); - let mut more_elements = false.into(); - let mut count = 0; - let mut elements = RemoteArray::empty(); - - unsafe { - self.interface()?.Browse( - item_id.as_pcwstr(), - continuation_point.as_mut_pwstr_ptr(), - max_elements, - browse_filter, - element_name_filter.as_pcwstr(), - vendor_filter.as_pcwstr(), - return_all_properties, - return_property_values, - property_ids, - &mut more_elements, - &mut count, - elements.as_mut_ptr(), - )?; - } - - if count > 0 { - unsafe { elements.set_len(count) }; - } - - Ok(( - more_elements.into(), - continuation_point.try_into()?, - elements, - )) - } -} diff --git a/opc_da/src/client/traits/browse_server_address_space.rs b/opc_da/src/client/traits/browse_server_address_space.rs deleted file mode 100644 index 37ab93f..0000000 --- a/opc_da/src/client/traits/browse_server_address_space.rs +++ /dev/null @@ -1,104 +0,0 @@ -use opc_da_bindings::{ - tagOPCBROWSEDIRECTION, tagOPCBROWSETYPE, tagOPCNAMESPACETYPE, IOPCBrowseServerAddressSpace, -}; - -use crate::utils::{LocalPointer, RemotePointer}; - -/// Server address space browsing functionality. -/// -/// Provides methods to navigate and discover items in the OPC server's address space. -/// Supports hierarchical and flat address spaces with filtering capabilities. -pub trait BrowseServerAddressSpaceTrait { - fn interface(&self) -> windows::core::Result<&IOPCBrowseServerAddressSpace>; - - /// Queries the organization type of the server's address space. - /// - /// # Returns - /// The namespace type (hierarchical or flat) - fn query_organization(&self) -> windows::core::Result { - unsafe { self.interface()?.QueryOrganization() } - } - - /// Changes the current position in the server's address space. - /// - /// # Arguments - /// * `browse_direction` - Direction to move (up, down, or to) - /// * `position` - Target position string (branch name for down/to) - /// - /// # Returns - /// Result indicating success or failure of position change - fn change_browse_position( - &self, - browse_direction: tagOPCBROWSEDIRECTION, - position: &str, - ) -> windows::core::Result<()> { - let position = LocalPointer::from(position); - - unsafe { - self.interface()? - .ChangeBrowsePosition(browse_direction, position.as_pwstr()) - } - } - - /// Browses available item IDs at the current position. - /// - /// # Arguments - /// * `browse_type` - Type of items to browse (leaf, branch, or flat) - /// * `filter_criteria` - Pattern for filtering items - /// * `datatype_filter` - VT_* type to filter by (0 for all) - /// * `access_rights_filter` - Required access rights - /// - /// # Returns - /// Enumerator for matching item IDs - fn browse_opc_item_ids( - &self, - browse_type: tagOPCBROWSETYPE, - filter_criteria: Option, - data_type_filter: u16, - access_rights_filter: u32, - ) -> windows::core::Result - where - S0: AsRef, - { - let filter_criteria = LocalPointer::from_option(filter_criteria); - - unsafe { - self.interface()?.BrowseOPCItemIDs( - browse_type, - filter_criteria.as_pwstr(), - data_type_filter, - access_rights_filter, - ) - } - } - - /// Gets fully qualified item ID from a leaf item. - /// - /// # Arguments - /// * `item_data_id` - Item name at current position - /// - /// # Returns - /// Fully qualified item ID string - fn get_item_id(&self, item_data_id: &str) -> windows::core::Result { - let item_data_id = LocalPointer::from(item_data_id); - - let output = unsafe { self.interface()?.GetItemID(item_data_id.as_pwstr())? }; - - RemotePointer::from(output).try_into() - } - - /// Browses available access paths for an item. - /// - /// # Arguments - /// * `item_id` - Fully qualified item ID - /// - /// # Returns - /// Enumerator for available access paths - fn browse_access_paths( - &self, - item_id: &str, - ) -> windows::core::Result { - let item_id = LocalPointer::from(item_id); - unsafe { self.interface()?.BrowseAccessPaths(item_id.as_pwstr()) } - } -} diff --git a/opc_da/src/client/traits/client.rs b/opc_da/src/client/traits/client.rs deleted file mode 100644 index ec7495f..0000000 --- a/opc_da/src/client/traits/client.rs +++ /dev/null @@ -1,108 +0,0 @@ -use windows_core::Interface as _; - -use crate::{ - client::GuidIterator, - def::{ClassContext, ServerInfo}, - utils::{IntoBridge, ToNative, TryToNative as _}, -}; - -/// Trait defining client functionality for OPC Data Access servers. -pub trait ClientTrait> { - /// GUID of the catalog used to enumerate servers. - const CATALOG_ID: windows::core::GUID; - - /// Retrieves an iterator over available server GUIDs. - /// - /// # Returns - /// - /// A `Result` containing a `GuidIterator` over server GUIDs, or an error if the operation fails. - fn get_servers(&self) -> windows::core::Result { - let id = unsafe { - windows::Win32::System::Com::CLSIDFromProgID(windows::core::w!("OPC.ServerList.1"))? - }; - - let servers: opc_comn_bindings::IOPCServerList = unsafe { - // TODO: Use CoCreateInstanceEx - windows::Win32::System::Com::CoCreateInstance( - &id, - None, - // TODO: Convert from filters - windows::Win32::System::Com::CLSCTX_ALL, - )? - }; - - let versions = [Self::CATALOG_ID]; - - let iter = unsafe { - servers - .EnumClassesOfCategories(&versions, &versions) - .map_err(|e| { - windows::core::Error::new(e.code(), "Failed to enumerate server classes") - })? - }; - - Ok(GuidIterator::new(iter)) - } - - /// Creates a server instance from the specified class ID. - /// - /// # Parameters - /// - /// - `class_id`: The GUID of the server class to instantiate. - /// - /// # Returns - /// - /// A `Result` containing the server instance, or an error if creation fails. - fn create_server( - &self, - class_id: windows::core::GUID, - class_context: ClassContext, - ) -> windows::core::Result { - let server: opc_da_bindings::IOPCServer = unsafe { - windows::Win32::System::Com::CoCreateInstance( - &class_id, - None, - class_context.to_native(), - )? - }; - - server.cast::()?.try_into() - } - - fn create_server2( - &self, - class_id: windows::core::GUID, - class_context: ClassContext, - server_info: Option, - ) -> windows::core::Result { - let mut results = [windows::Win32::System::Com::MULTI_QI { - pIID: &windows::core::IUnknown::IID, - pItf: core::mem::ManuallyDrop::new(None), - hr: windows::core::HRESULT(0), - }]; - - unsafe { - windows::Win32::System::Com::CoCreateInstanceEx( - &class_id, - None, - class_context.to_native(), - match server_info { - Some(info) => Some(&info.into_bridge().try_to_native()?), - None => None, - }, - &mut results, - )? - }; - - if results[0].hr.is_err() { - return Err(results[0].hr.into()); - } - - match results[0].pItf.as_ref() { - Some(itf) => itf.cast::()?.try_into(), - None => Err(windows::core::Error::from( - windows::Win32::Foundation::E_POINTER, - )), - } - } -} diff --git a/opc_da/src/client/traits/common.rs b/opc_da/src/client/traits/common.rs deleted file mode 100644 index fac1bd5..0000000 --- a/opc_da/src/client/traits/common.rs +++ /dev/null @@ -1,71 +0,0 @@ -use opc_comn_bindings::IOPCCommon; - -use crate::utils::{LocalPointer, RemoteArray, RemotePointer}; - -/// Common OPC server functionality trait. -/// -/// Provides methods for locale management and error string retrieval. -/// This trait is implemented by all OPC DA servers to support basic -/// configuration and error handling capabilities. -pub trait CommonTrait { - fn interface(&self) -> windows::core::Result<&IOPCCommon>; - - /// Sets the locale ID for server string localization. - /// - /// # Arguments - /// * `locale_id` - Windows LCID (Locale ID) value for the desired language - /// - /// # Returns - /// Result indicating if the locale was successfully set - fn set_locale_id(&self, locale_id: u32) -> windows::core::Result<()> { - unsafe { self.interface()?.SetLocaleID(locale_id) } - } - - /// Gets the current locale ID used by the server. - /// - /// # Returns - /// Windows LCID value representing the current locale - fn get_locale_id(&self) -> windows::core::Result { - unsafe { self.interface()?.GetLocaleID() } - } - - /// Gets a list of locale IDs supported by the server. - /// - /// # Returns - /// Array of Windows LCID values for supported locales - fn query_available_locale_ids(&self) -> windows::core::Result> { - let mut locale_ids = RemoteArray::empty(); - - unsafe { - self.interface()? - .QueryAvailableLocaleIDs(locale_ids.as_mut_len_ptr(), locale_ids.as_mut_ptr())?; - } - - Ok(locale_ids) - } - - /// Gets a localized error description string. - /// - /// # Arguments - /// * `error` - HRESULT error code to get description for - /// - /// # Returns - /// Localized error message string in current locale - fn get_error_string(&self, error: windows::core::HRESULT) -> windows::core::Result { - let output = unsafe { self.interface()?.GetErrorString(error)? }; - - RemotePointer::from(output).try_into() - } - - /// Sets a client name for server identification. - /// - /// # Arguments - /// * `name` - Client application name or description - /// - /// # Returns - /// Result indicating if the client name was successfully set - fn set_client_name(&self, name: &str) -> windows::core::Result<()> { - let name = LocalPointer::from(name); - unsafe { self.interface()?.SetClientName(name.as_pcwstr()) } - } -} diff --git a/opc_da/src/client/traits/connection_point_container.rs b/opc_da/src/client/traits/connection_point_container.rs deleted file mode 100644 index 541f40f..0000000 --- a/opc_da/src/client/traits/connection_point_container.rs +++ /dev/null @@ -1,62 +0,0 @@ -use windows::core::{Interface as _, GUID}; - -/// COM connection point container functionality. -/// -/// Provides methods to establish connections between event sources -/// and event sinks in the OPC COM architecture. Used primarily for -/// handling asynchronous callbacks. -pub trait ConnectionPointContainerTrait { - fn interface( - &self, - ) -> windows::core::Result<&windows::Win32::System::Com::IConnectionPointContainer>; - - /// Finds a connection point for a specific interface. - /// - /// # Arguments - /// * `id` - GUID of the connection point interface to find - /// - /// # Returns - /// Connection point interface for the specified GUID - /// - /// # Safety - /// Caller must ensure: - /// - COM is properly initialized - /// - The underlying COM object is valid - /// - /// # Errors - /// Returns an error if: - /// - The COM operation fails - /// - The connection point is not found - fn find_connection_point( - &self, - id: &GUID, - ) -> windows::core::Result { - unsafe { self.interface()?.FindConnectionPoint(id) } - } - - fn data_callback_connection_point( - &self, - ) -> windows::core::Result { - self.find_connection_point(&opc_da_bindings::IOPCDataCallback::IID) - } - - /// Enumerates all available connection points. - /// - /// # Returns - /// Enumerator for iterating through available connection points - /// - /// # Safety - /// Caller must ensure: - /// - COM is properly initialized - /// - The underlying COM object is valid - /// - /// # Errors - /// Returns an error if: - /// - The COM operation fails - /// - No connection points are available - fn enum_connection_points( - &self, - ) -> windows::core::Result { - unsafe { self.interface()?.EnumConnectionPoints() } - } -} diff --git a/opc_da/src/client/traits/data_callback.rs b/opc_da/src/client/traits/data_callback.rs deleted file mode 100644 index dcd52fb..0000000 --- a/opc_da/src/client/traits/data_callback.rs +++ /dev/null @@ -1,131 +0,0 @@ -use crate::{ - def::{CancelCompleteEvent, DataChangeEvent, ReadCompleteEvent, WriteCompleteEvent}, - utils::RemoteArray, -}; - -#[windows::core::implement( - // implicit implement IUnknown - opc_da_bindings::IOPCDataCallback, -)] -pub struct DataCallback<'a, T>(pub &'a T) -where - T: DataCallbackTrait; - -impl std::ops::Deref for DataCallback<'_, T> -where - T: DataCallbackTrait, -{ - type Target = T; - - fn deref(&self) -> &Self::Target { - self.0 - } -} - -pub trait DataCallbackTrait { - #[allow(clippy::too_many_arguments)] - fn on_data_change(&self, event: DataChangeEvent) -> windows_core::Result<()>; - - #[allow(clippy::too_many_arguments)] - fn on_read_complete(&self, event: ReadCompleteEvent) -> windows_core::Result<()>; - - fn on_write_complete(&self, event: WriteCompleteEvent) -> windows_core::Result<()>; - - fn on_cancel_complete(&self, event: CancelCompleteEvent) -> windows_core::Result<()>; -} - -impl<'a, T: DataCallbackTrait + 'a> opc_da_bindings::IOPCDataCallback_Impl - for DataCallback_Impl<'a, T> -{ - fn OnDataChange( - &self, - transaction_id: u32, - group_handle: u32, - master_quality: windows_core::HRESULT, - master_error: windows_core::HRESULT, - count: u32, - client_items: *const u32, - values: *const windows::Win32::System::Variant::VARIANT, - qualities: *const u16, - timestamps: *const windows::Win32::Foundation::FILETIME, - errors: *const windows_core::HRESULT, - ) -> windows_core::Result<()> { - let client_items = RemoteArray::from_ptr(client_items, count); - let values = RemoteArray::from_ptr(values, count); - let qualities = RemoteArray::from_ptr(qualities, count); - let timestamps = RemoteArray::from_ptr(timestamps, count); - let errors = RemoteArray::from_ptr(errors, count); - - self.on_data_change(DataChangeEvent { - transaction_id, - group_handle, - master_quality, - master_error, - client_items, - values, - qualities, - timestamps, - errors, - }) - } - - fn OnReadComplete( - &self, - transaction_id: u32, - group_handle: u32, - master_quality: windows_core::HRESULT, - master_error: windows_core::HRESULT, - count: u32, - client_items: *const u32, - values: *const windows::Win32::System::Variant::VARIANT, - qualities: *const u16, - timestamps: *const windows::Win32::Foundation::FILETIME, - errors: *const windows_core::HRESULT, - ) -> windows_core::Result<()> { - let client_items = RemoteArray::from_ptr(client_items, count); - let values = RemoteArray::from_ptr(values, count); - let qualities = RemoteArray::from_ptr(qualities, count); - let timestamps = RemoteArray::from_ptr(timestamps, count); - let errors = RemoteArray::from_ptr(errors, count); - - self.on_read_complete(ReadCompleteEvent { - transaction_id, - group_handle, - master_quality, - master_error, - client_items, - values, - qualities, - timestamps, - errors, - }) - } - - fn OnWriteComplete( - &self, - transaction_id: u32, - group_handle: u32, - master_error: windows_core::HRESULT, - count: u32, - client_handles: *const u32, - errors: *const windows_core::HRESULT, - ) -> windows_core::Result<()> { - let client_handles = RemoteArray::from_ptr(client_handles, count); - let errors = RemoteArray::from_ptr(errors, count); - - self.on_write_complete(WriteCompleteEvent { - transaction_id, - group_handle, - master_error, - client_handles, - errors, - }) - } - - fn OnCancelComplete(&self, transaction_id: u32, group_handle: u32) -> windows_core::Result<()> { - self.on_cancel_complete(CancelCompleteEvent { - transaction_id, - group_handle, - }) - } -} diff --git a/opc_da/src/client/traits/data_object.rs b/opc_da/src/client/traits/data_object.rs deleted file mode 100644 index 0344977..0000000 --- a/opc_da/src/client/traits/data_object.rs +++ /dev/null @@ -1,131 +0,0 @@ -use windows::Win32::System::Com::{FORMATETC, STGMEDIUM}; - -/// Data transfer functionality using COM's structured storage. -/// -/// Provides methods to transfer data between client and server using -/// structured storage formats and advisory connections. -pub trait DataObjectTrait { - fn interface(&self) -> windows::core::Result<&windows::Win32::System::Com::IDataObject>; - - /// Gets data from the object in the specified format. - /// - /// # Arguments - /// * `format` - Format specification including clipboard format and storage medium - /// - /// # Returns - /// Storage medium containing the requested data - fn get_data(&self, format: &FORMATETC) -> windows::core::Result { - unsafe { self.interface()?.GetData(format) } - } - - /// Gets data in place using the specified format. - /// - /// # Arguments - /// * `format` - Format specification including clipboard format and storage medium - /// - /// # Returns - /// Storage medium updated with the requested data - fn get_data_here(&self, format: &FORMATETC) -> windows::core::Result { - let mut output = STGMEDIUM::default(); - unsafe { self.interface()?.GetDataHere(format, &mut output)? }; - Ok(output) - } - - /// Tests if data is available in the specified format. - /// - /// # Arguments - /// * `format` - Format specification to test for availability - /// - /// # Returns - /// Ok(()) if the format is supported, error otherwise - fn query_get_data(&self, format: &FORMATETC) -> windows::core::Result<()> { - unsafe { self.interface()?.QueryGetData(format) }.ok() - } - - /// Gets the canonical format equivalent to the specified format. - /// - /// # Arguments - /// * `format_in` - Format specification to convert - /// - /// # Returns - /// Canonical format specification - fn get_canonical_format(&self, format_in: &FORMATETC) -> windows::core::Result { - let mut output = FORMATETC::default(); - unsafe { - self.interface()? - .GetCanonicalFormatEtc(format_in, &mut output) - } - .ok()?; - - Ok(output) - } - - /// Sets data in the specified format. - /// - /// # Arguments - /// * `format` - Format specification for the data - /// * `medium` - Storage medium containing the data - /// * `release` - If true, the object takes ownership of medium - /// - /// # Returns - /// Ok(()) if data was set successfully - fn set_data( - &self, - format: &FORMATETC, - medium: &STGMEDIUM, - release: bool, - ) -> windows::core::Result<()> { - unsafe { self.interface()?.SetData(format, medium, release) } - } - - /// Enumerates available data formats. - /// - /// # Arguments - /// * `direction` - Direction of data flow (DATADIR_GET = 1, DATADIR_SET = 2) - /// - /// # Returns - /// Enumerator for available format specifications - fn enumerate_formats( - &self, - direction: u32, - ) -> windows::core::Result { - unsafe { self.interface()?.EnumFormatEtc(direction) } - } - - /// Establishes an advisory connection for data change notifications. - /// - /// # Arguments - /// * `format` - Format specification to monitor - /// * `advf` - Advisory flags controlling notification behavior - /// * `sink` - Sink interface to receive notifications - /// - /// # Returns - /// Connection token for the advisory connection - fn dadvise( - &self, - format: &FORMATETC, - advf: u32, - sink: &windows::Win32::System::Com::IAdviseSink, - ) -> windows::core::Result { - unsafe { self.interface()?.DAdvise(format, advf, sink) } - } - - /// Terminates an advisory connection. - /// - /// # Arguments - /// * `connection` - Connection token from dadvise - /// - /// # Returns - /// Ok(()) if connection was terminated successfully - fn dunadvise(&self, connection: u32) -> windows::core::Result<()> { - unsafe { self.interface()?.DUnadvise(connection) } - } - - /// Enumerates active advisory connections. - /// - /// # Returns - /// Enumerator for active advisory connections - fn enum_dadvise(&self) -> windows::core::Result { - unsafe { self.interface()?.EnumDAdvise() } - } -} diff --git a/opc_da/src/client/traits/group_state_mgt.rs b/opc_da/src/client/traits/group_state_mgt.rs deleted file mode 100644 index 9b4a7f4..0000000 --- a/opc_da/src/client/traits/group_state_mgt.rs +++ /dev/null @@ -1,112 +0,0 @@ -use crate::{ - def::GroupState, - utils::{LocalPointer, RemotePointer}, -}; - -/// Group state management functionality. -/// -/// Provides methods to get and set various group state parameters including: -/// - Update rate -/// - Active state -/// - Time bias -/// - Deadband -/// - Locale ID -/// - Group handles -pub trait GroupStateMgtTrait { - fn interface(&self) -> windows::core::Result<&opc_da_bindings::IOPCGroupStateMgt>; - - /// Gets the current state of the group. - /// - /// Returns a GroupState structure containing all group parameters. - fn get_state(&self) -> windows::core::Result { - let mut state = GroupState::default(); - let mut active = windows_core::BOOL::default(); - let name = { - let mut name = RemotePointer::null(); - unsafe { - self.interface()?.GetState( - &mut state.update_rate, - &mut active, - name.as_mut_pwstr_ptr(), - &mut state.time_bias, - &mut state.percent_deadband, - &mut state.locale_id, - &mut state.client_handle, - &mut state.server_handle, - )?; - } - name - }; - - state.active = active.as_bool(); - state.name = name.try_into()?; - - Ok(state) - } - - /// Sets one or more group state parameters. - /// - /// # Arguments - /// * `update_rate` - Requested group update rate in milliseconds - /// * `active` - Group active state - /// * `time_bias` - Time bias from UTC in minutes - /// * `percent_deadband` - Percent deadband for analog items - /// * `locale_id` - Locale ID for status/error strings - /// * `client_handle` - Client-provided handle - /// - /// # Returns - /// The actual update rate set by the server - fn set_state( - &self, - update_rate: Option, - active: Option, - time_bias: Option, - percent_deadband: Option, - locale_id: Option, - client_handle: Option, - ) -> windows::core::Result { - let requested_update_rate = LocalPointer::new(update_rate); - let mut revised_update_rate = LocalPointer::new(Some(0)); - let active = LocalPointer::new(active.map(windows_core::BOOL::from)); - let time_bias = LocalPointer::new(time_bias); - let percent_deadband = LocalPointer::new(percent_deadband); - let locale_id = LocalPointer::new(locale_id); - let client_handle = LocalPointer::new(client_handle); - - unsafe { - self.interface()?.SetState( - requested_update_rate.as_ptr(), - revised_update_rate.as_mut_ptr(), - active.as_ptr(), - time_bias.as_ptr(), - percent_deadband.as_ptr(), - locale_id.as_ptr(), - client_handle.as_ptr(), - ) - }?; - - Ok(revised_update_rate.into_inner().unwrap_or_default()) - } - - /// Sets the name of the group. - fn set_name(&self, name: &str) -> windows::core::Result<()> { - let name = LocalPointer::from(name); - - unsafe { self.interface()?.SetName(name.as_pwstr()) } - } - - /// Creates a copy of the group with a new name. - /// - /// # Arguments - /// * `name` - Name for the new group - /// * `id` - Client-provided GUID for the new group - fn clone_group( - &self, - name: &str, - id: &windows::core::GUID, - ) -> windows::core::Result { - let name = LocalPointer::from(name); - - unsafe { self.interface()?.CloneGroup(name.as_pwstr(), id) } - } -} diff --git a/opc_da/src/client/traits/group_state_mgt2.rs b/opc_da/src/client/traits/group_state_mgt2.rs deleted file mode 100644 index c1f9ba1..0000000 --- a/opc_da/src/client/traits/group_state_mgt2.rs +++ /dev/null @@ -1,33 +0,0 @@ -/// Extended group state management trait (OPC DA 3.0). -/// -/// Provides methods to manage the keep-alive time for OPC groups. The keep-alive time -/// determines how often the server sends keep-alive notifications to maintain the -/// connection state, even when no data has changed. -pub trait GroupStateMgt2Trait { - fn interface(&self) -> windows::core::Result<&opc_da_bindings::IOPCGroupStateMgt2>; - - /// Sets the keep-alive time for the group in milliseconds. - /// - /// # Arguments - /// * `keep_alive_time` - The requested keep-alive time in milliseconds - /// - /// # Returns - /// The actual keep-alive time set by the server, which may differ from - /// the requested time based on server capabilities - /// - /// # Notes - /// The server may not support the exact requested time and will return - /// the closest supported value. A value of 0 typically disables keep-alive. - fn set_keep_alive(&self, keep_alive_time: u32) -> windows::core::Result { - unsafe { self.interface()?.SetKeepAlive(keep_alive_time) } - } - - /// Gets the current keep-alive time for the group. - /// - /// # Returns - /// The current keep-alive time in milliseconds. A value of 0 indicates - /// that keep-alive is disabled. - fn get_keep_alive(&self) -> windows::core::Result { - unsafe { self.interface()?.GetKeepAlive() } - } -} diff --git a/opc_da/src/client/traits/item_deadband_mgt.rs b/opc_da/src/client/traits/item_deadband_mgt.rs deleted file mode 100644 index d0850d4..0000000 --- a/opc_da/src/client/traits/item_deadband_mgt.rs +++ /dev/null @@ -1,113 +0,0 @@ -use crate::utils::RemoteArray; - -/// Item deadband management functionality (OPC DA 3.0). -/// -/// Provides methods to manage per-item deadband values. Deadband settings -/// control the minimum value change required before the server reports -/// a data change to the client. -pub trait ItemDeadbandMgtTrait { - fn interface(&self) -> windows::core::Result<&opc_da_bindings::IOPCItemDeadbandMgt>; - - /// Sets deadband values for specified items. - /// - /// # Arguments - /// * `server_handles` - Array of server item handles - /// * `deadbands` - Array of deadband percentages (0.0 to 100.0) - /// - /// # Returns - /// Array of HRESULT values indicating per-item status - /// - /// # Errors - /// Returns E_INVALIDARG if arrays have different lengths - fn set_item_deadband( - &self, - server_handles: &[u32], - deadbands: &[f32], - ) -> windows::core::Result> { - if server_handles.len() != deadbands.len() { - return Err(windows::core::Error::new( - windows::Win32::Foundation::E_INVALIDARG, - "server_handles and deadbands must have the same length", - )); - } - - // Validate deadband values (0.0 to 100.0) - if deadbands.iter().any(|&v| !(0.0..=100.0).contains(&v)) { - return Err(windows::core::Error::new( - windows::Win32::Foundation::E_INVALIDARG, - "deadband values must be between 0.0 and 100.0", - )); - } - - let len = server_handles.len().try_into()?; - - let mut errors = RemoteArray::new(len); - - unsafe { - self.interface()?.SetItemDeadband( - len, - server_handles.as_ptr(), - deadbands.as_ptr(), - errors.as_mut_ptr(), - )?; - } - - Ok(errors) - } - - /// Gets current deadband values for specified items. - /// - /// # Arguments - /// * `server_handles` - Array of server item handles - /// - /// # Returns - /// Tuple containing: - /// - Array of deadband percentages (0.0 to 100.0) - /// - Array of HRESULT values indicating per-item status - fn get_item_deadband( - &self, - server_handles: &[u32], - ) -> windows::core::Result<(RemoteArray, RemoteArray)> { - let len = server_handles.len().try_into()?; - - let mut errors = RemoteArray::new(len); - let mut deadbands = RemoteArray::new(len); - - unsafe { - self.interface()?.GetItemDeadband( - len, - server_handles.as_ptr(), - deadbands.as_mut_ptr(), - errors.as_mut_ptr(), - )?; - } - - Ok((deadbands, errors)) - } - - /// Removes deadband settings for specified items. - /// - /// # Arguments - /// * `server_handles` - Array of server item handles - /// - /// # Returns - /// Array of HRESULT values indicating per-item status - fn clear_item_deadband( - &self, - server_handles: &[u32], - ) -> windows::core::Result> { - let len = server_handles.len().try_into()?; - - let mut errors = RemoteArray::new(len); - - unsafe { - self.interface()?.ClearItemDeadband( - len, - server_handles.as_ptr(), - errors.as_mut_ptr(), - )?; - } - - Ok(errors) - } -} diff --git a/opc_da/src/client/traits/item_io.rs b/opc_da/src/client/traits/item_io.rs deleted file mode 100644 index 1c673a3..0000000 --- a/opc_da/src/client/traits/item_io.rs +++ /dev/null @@ -1,110 +0,0 @@ -use crate::utils::{LocalPointer, RemoteArray}; -use opc_da_bindings::{tagOPCITEMVQT, IOPCItemIO}; - -/// Direct item I/O functionality (OPC DA 3.0). -/// -/// Provides methods for direct read/write operations on items without requiring -/// group creation. This trait offers a simplified interface for basic data access. -pub trait ItemIoTrait { - fn interface(&self) -> windows::core::Result<&IOPCItemIO>; - - /// Reads values directly from items with age constraints. - /// - /// # Arguments - /// * `item_ids` - Array of fully qualified item IDs to read - /// * `max_age` - Maximum age constraints for each item in milliseconds - /// - /// # Returns - /// Tuple containing: - /// - Array of item values (VARIANT) - /// - Array of quality values - /// - Array of timestamps - /// - Array of per-item error codes - /// - /// # Errors - /// Returns E_INVALIDARG if arrays are empty or have different lengths - #[allow(clippy::type_complexity)] - fn read( - &self, - item_ids: &[String], - max_age: &[u32], - ) -> windows::core::Result<( - RemoteArray, - RemoteArray, - RemoteArray, - RemoteArray, - )> { - if item_ids.is_empty() || max_age.is_empty() || item_ids.len() != max_age.len() { - return Err(windows::core::Error::new( - windows::Win32::Foundation::E_INVALIDARG, - "Invalid arguments - arrays must be non-empty and have same length", - )); - } - - let item_ptrs: LocalPointer>> = LocalPointer::from(item_ids); - let item_ptrs = item_ptrs.as_pcwstr_array(); - - let len = item_ids.len().try_into()?; - - let mut values = RemoteArray::new(len); - let mut qualities = RemoteArray::new(len); - let mut timestamps = RemoteArray::new(len); - let mut errors = RemoteArray::new(len); - - unsafe { - self.interface()?.Read( - item_ids.len() as u32, - item_ptrs.as_ptr(), - max_age.as_ptr(), - values.as_mut_ptr(), - qualities.as_mut_ptr(), - timestamps.as_mut_ptr(), - errors.as_mut_ptr(), - )?; - } - - Ok((values, qualities, timestamps, errors)) - } - - /// Writes values with quality and timestamp information. - /// - /// # Arguments - /// * `item_ids` - Array of fully qualified item IDs to write - /// * `item_vqts` - Array of value-quality-timestamp structures - /// - /// # Returns - /// Array of per-item error codes - /// - /// # Errors - /// Returns E_INVALIDARG if arrays are empty or have different lengths - fn write_vqt( - &self, - item_ids: &[String], - item_vqts: &[tagOPCITEMVQT], - ) -> windows::core::Result> { - if item_ids.is_empty() || item_vqts.is_empty() || item_ids.len() != item_vqts.len() { - return Err(windows::core::Error::new( - windows::Win32::Foundation::E_INVALIDARG, - "Invalid arguments - arrays must be non-empty and have same length", - )); - } - - let len = item_ids.len().try_into()?; - - let item_ptrs = LocalPointer::from(item_ids); - let item_ptrs = item_ptrs.as_pcwstr_array(); - - let mut errors = RemoteArray::new(len); - - unsafe { - self.interface()?.WriteVQT( - len, - item_ptrs.as_ptr(), - item_vqts.as_ptr(), - errors.as_mut_ptr(), - )?; - } - - Ok(errors) - } -} diff --git a/opc_da/src/client/traits/item_mgt.rs b/opc_da/src/client/traits/item_mgt.rs deleted file mode 100644 index 030e95f..0000000 --- a/opc_da/src/client/traits/item_mgt.rs +++ /dev/null @@ -1,274 +0,0 @@ -use windows::core::Interface as _; - -use crate::{client::ItemAttributeIterator, utils::RemoteArray}; - -/// Item management functionality. -/// -/// Provides methods to manage OPC items within a group, including adding, -/// removing, and modifying item properties such as active state, client -/// handles, and data types. -pub trait ItemMgtTrait { - fn interface(&self) -> windows::core::Result<&opc_da_bindings::IOPCItemMgt>; - - /// Adds items to the group. - /// - /// # Arguments - /// * `items` - Array of item definitions containing item IDs and requested properties - /// - /// # Returns - /// Tuple containing: - /// - Array of item results with server handles and canonical data type - /// - Array of per-item error codes - /// - /// # Errors - /// Returns E_INVALIDARG if items array is empty - fn add_items( - &self, - items: &[opc_da_bindings::tagOPCITEMDEF], - ) -> windows::core::Result<( - RemoteArray, - RemoteArray, - )> { - if items.is_empty() { - return Err(windows_core::Error::new( - windows::Win32::Foundation::E_INVALIDARG, - "items cannot be empty", - )); - } - - let len = items.len().try_into()?; - let mut results = RemoteArray::new(len); - let mut errors = RemoteArray::new(len); - - unsafe { - self.interface()?.AddItems( - len, - items.as_ptr(), - results.as_mut_ptr(), - errors.as_mut_ptr(), - )?; - } - - Ok((results, errors)) - } - - /// Validates item definitions without adding them to the group. - /// - /// # Arguments - /// * `items` - Array of item definitions to validate - /// * `blob_update` - Whether to validate blob update capability - /// - /// # Returns - /// Tuple containing: - /// - Array of item results with access rights and canonical data type - /// - Array of per-item error codes - fn validate_items( - &self, - items: &[opc_da_bindings::tagOPCITEMDEF], - blob_update: bool, - ) -> windows::core::Result<( - RemoteArray, - RemoteArray, - )> { - if items.is_empty() { - return Err(windows_core::Error::new( - windows::Win32::Foundation::E_INVALIDARG, - "items cannot be empty", - )); - } - - let len = items.len().try_into()?; - let mut results = RemoteArray::new(len); - let mut errors = RemoteArray::new(len); - - unsafe { - self.interface()?.ValidateItems( - len, - items.as_ptr(), - blob_update, - results.as_mut_ptr(), - errors.as_mut_ptr(), - )?; - } - - Ok((results, errors)) - } - - /// Removes items from the group. - /// - /// # Arguments - /// * `server_handles` - Array of server handles for items to remove - /// - /// # Returns - /// Array of per-item error codes - /// - /// # Errors - /// Returns E_INVALIDARG if server_handles is empty - fn remove_items( - &self, - server_handles: &[u32], - ) -> windows::core::Result> { - if server_handles.is_empty() { - return Err(windows_core::Error::new( - windows::Win32::Foundation::E_INVALIDARG, - "server_handles cannot be empty", - )); - } - - let len = server_handles.len().try_into()?; - let mut errors = RemoteArray::new(len); - - unsafe { - self.interface()? - .RemoveItems(len, server_handles.as_ptr(), errors.as_mut_ptr())?; - } - - Ok(errors) - } - - /// Sets the active state of items. - /// - /// # Arguments - /// * `server_handles` - Array of server handles - /// * `active` - True to activate items, false to deactivate - /// - /// # Returns - /// Array of per-item error codes - /// - /// # Errors - /// Returns E_INVALIDARG if server_handles is empty - fn set_active_state( - &self, - server_handles: &[u32], - active: bool, - ) -> windows::core::Result> { - if server_handles.is_empty() { - return Err(windows_core::Error::new( - windows::Win32::Foundation::E_INVALIDARG, - "server_handles cannot be empty", - )); - } - - let len = server_handles.len().try_into()?; - let mut errors = RemoteArray::new(len); - - unsafe { - self.interface()?.SetActiveState( - len, - server_handles.as_ptr(), - active, - errors.as_mut_ptr(), - )?; - } - - Ok(errors) - } - - /// Sets client handles for items. - /// - /// # Arguments - /// * `server_handles` - Array of server handles - /// * `client_handles` - Array of new client handles - /// - /// # Returns - /// Array of per-item error codes - /// - /// # Errors - /// Returns E_INVALIDARG if arrays are empty or have different lengths - fn set_client_handles( - &self, - server_handles: &[u32], - client_handles: &[u32], - ) -> windows::core::Result> { - if server_handles.len() != client_handles.len() { - return Err(windows_core::Error::new( - windows::Win32::Foundation::E_INVALIDARG, - "server_handles and client_handles must have the same length", - )); - } - - if server_handles.is_empty() { - return Err(windows_core::Error::new( - windows::Win32::Foundation::E_INVALIDARG, - "server_handles cannot be empty", - )); - } - - let len = server_handles.len().try_into()?; - let mut errors = RemoteArray::new(len); - - unsafe { - self.interface()?.SetClientHandles( - len, - server_handles.as_ptr(), - client_handles.as_ptr(), - errors.as_mut_ptr(), - )?; - } - - Ok(errors) - } - - /// Sets requested data types for items. - /// - /// # Arguments - /// * `server_handles` - Array of server handles - /// * `requested_datatypes` - Array of VT_* data types - /// - /// # Returns - /// Array of per-item error codes - /// - /// # Errors - /// Returns E_INVALIDARG if arrays are empty or have different lengths - fn set_datatypes( - &self, - server_handles: &[u32], - requested_datatypes: &[u16], - ) -> windows::core::Result> { - if server_handles.len() != requested_datatypes.len() { - return Err(windows_core::Error::new( - windows::Win32::Foundation::E_INVALIDARG, - "server_handles and requested_datatypes must have the same length", - )); - } - - if server_handles.is_empty() { - return Err(windows_core::Error::new( - windows::Win32::Foundation::E_INVALIDARG, - "server_handles cannot be empty", - )); - } - - let len = server_handles.len().try_into()?; - let mut errors = RemoteArray::new(len); - - unsafe { - self.interface()?.SetDatatypes( - len, - server_handles.as_ptr(), - requested_datatypes.as_ptr(), - errors.as_mut_ptr(), - )?; - } - - Ok(errors) - } - - /// Creates an enumerator for item management. - /// - /// # Arguments - /// * `id` - Interface ID specifying the type of enumerator - /// - /// # Returns - /// Enumerator interface for iterating through items - fn create_enumerator(&self) -> windows::core::Result { - let enumerator = unsafe { - self.interface()? - .CreateEnumerator(&opc_da_bindings::IEnumOPCItemAttributes::IID)? - }; - - Ok(ItemAttributeIterator::new(enumerator.cast()?)) - } -} - -// ...existing code... diff --git a/opc_da/src/client/traits/item_properties.rs b/opc_da/src/client/traits/item_properties.rs deleted file mode 100644 index d1383fd..0000000 --- a/opc_da/src/client/traits/item_properties.rs +++ /dev/null @@ -1,159 +0,0 @@ -use crate::utils::{LocalPointer, RemoteArray}; -use opc_da_bindings::IOPCItemProperties; - -/// Item properties management functionality. -/// -/// Provides methods to query and retrieve item property information from -/// the OPC server. Properties include metadata such as engineering units, -/// descriptions, and other vendor-specific attributes. -pub trait ItemPropertiesTrait { - fn interface(&self) -> windows::core::Result<&IOPCItemProperties>; - - /// Queries available properties for a specific item. - /// - /// # Arguments - /// * `item_id` - Fully qualified item ID - /// - /// # Returns - /// Tuple containing: - /// - Array of property IDs - /// - Array of property descriptions - /// - Array of property data types (VT_*) - /// - /// # Errors - /// Returns E_INVALIDARG if item_id is empty - fn query_available_properties( - &self, - item_id: &str, - ) -> windows::core::Result<( - RemoteArray, // property IDs - RemoteArray, // descriptions - RemoteArray, // datatypes - )> { - if item_id.is_empty() { - return Err(windows::core::Error::new( - windows::Win32::Foundation::E_INVALIDARG, - "item_id is empty", - )); - } - - let item_id = LocalPointer::from(item_id); - - let mut count = 0; - let mut property_ids = RemoteArray::new(0); - let mut descriptions = RemoteArray::new(0); - let mut datatypes = RemoteArray::new(0); - - unsafe { - self.interface()?.QueryAvailableProperties( - item_id.as_pcwstr(), - &mut count, - property_ids.as_mut_ptr(), - descriptions.as_mut_ptr(), - datatypes.as_mut_ptr(), - )?; - } - - if count > 0 { - unsafe { - property_ids.set_len(count); - descriptions.set_len(count); - datatypes.set_len(count); - } - } - - Ok((property_ids, descriptions, datatypes)) - } - - /// Gets property values for a specific item. - /// - /// # Arguments - /// * `item_id` - Fully qualified item ID - /// * `property_ids` - Array of property IDs to retrieve - /// - /// # Returns - /// Tuple containing: - /// - Array of property values as VARIANTs - /// - Array of per-property error codes - /// - /// # Errors - /// Returns E_INVALIDARG if property_ids is empty - fn get_item_properties( - &self, - item_id: &str, - property_ids: &[u32], - ) -> windows::core::Result<( - RemoteArray, - RemoteArray, - )> { - if property_ids.is_empty() { - return Err(windows::core::Error::new( - windows::Win32::Foundation::E_INVALIDARG, - "property_ids is empty", - )); - } - - let item_id = LocalPointer::from(item_id); - - let mut values = RemoteArray::new(property_ids.len().try_into()?); - let mut errors = RemoteArray::new(property_ids.len().try_into()?); - - unsafe { - self.interface()?.GetItemProperties( - item_id.as_pcwstr(), - property_ids.len() as u32, - property_ids.as_ptr(), - values.as_mut_ptr(), - errors.as_mut_ptr(), - )?; - } - - Ok((values, errors)) - } - - /// Looks up item IDs for properties that are themselves OPC items. - /// - /// # Arguments - /// * `item_id` - Base item ID to look up properties for - /// * `property_ids` - Array of property IDs to look up - /// - /// # Returns - /// Tuple containing: - /// - Array of property-specific item IDs - /// - Array of per-property error codes - /// - /// # Errors - /// Returns E_INVALIDARG if property_ids is empty - fn lookup_item_ids( - &self, - item_id: &str, - property_ids: &[u32], - ) -> windows::core::Result<( - RemoteArray, - RemoteArray, - )> { - if property_ids.is_empty() { - return Err(windows::core::Error::new( - windows::Win32::Foundation::E_INVALIDARG, - "property_ids is empty", - )); - } - - let item_id = LocalPointer::from(item_id); - - let mut new_item_ids = RemoteArray::new(property_ids.len().try_into()?); - let mut errors = RemoteArray::new(property_ids.len().try_into()?); - - unsafe { - self.interface()?.LookupItemIDs( - item_id.as_pcwstr(), - property_ids.len().try_into()?, - property_ids.as_ptr(), - new_item_ids.as_mut_ptr(), - errors.as_mut_ptr(), - )?; - } - - Ok((new_item_ids, errors)) - } -} diff --git a/opc_da/src/client/traits/item_sampling_mgt.rs b/opc_da/src/client/traits/item_sampling_mgt.rs deleted file mode 100644 index f4c5421..0000000 --- a/opc_da/src/client/traits/item_sampling_mgt.rs +++ /dev/null @@ -1,182 +0,0 @@ -use crate::utils::RemoteArray; -use windows_core::BOOL; - -/// Item sampling management functionality (OPC DA 3.0). -/// -/// Provides methods to control sampling rates and buffering behavior -/// for individual items in an OPC group. -pub trait ItemSamplingMgtTrait { - fn interface(&self) -> windows::core::Result<&opc_da_bindings::IOPCItemSamplingMgt>; - - /// Sets sampling rates for specified items. - /// - /// # Arguments - /// * `server_handles` - Array of server item handles - /// * `sampling_rates` - Array of requested sampling rates in milliseconds - /// - /// # Returns - /// Tuple containing: - /// - Array of actual sampling rates set by server - /// - Array of per-item error codes - /// - /// # Errors - /// Returns E_INVALIDARG if arrays have different lengths - fn set_item_sampling_rate( - &self, - server_handles: &[u32], - sampling_rates: &[u32], - ) -> windows::core::Result<(RemoteArray, RemoteArray)> { - if server_handles.len() != sampling_rates.len() { - return Err(windows::core::Error::new( - windows::Win32::Foundation::E_INVALIDARG, - "server_handles and sampling_rates must have the same length", - )); - } - - let len = server_handles.len().try_into()?; - - let mut revised_rates = RemoteArray::new(len); - let mut errors = RemoteArray::new(len); - - unsafe { - self.interface()?.SetItemSamplingRate( - len, - server_handles.as_ptr(), - sampling_rates.as_ptr(), - revised_rates.as_mut_ptr(), - errors.as_mut_ptr(), - )?; - } - - Ok((revised_rates, errors)) - } - - /// Gets current sampling rates for specified items. - /// - /// # Arguments - /// * `server_handles` - Array of server item handles - /// - /// # Returns - /// Tuple containing: - /// - Array of current sampling rates in milliseconds - /// - Array of per-item error codes - fn get_item_sampling_rate( - &self, - server_handles: &[u32], - ) -> windows::core::Result<(RemoteArray, RemoteArray)> { - let len = server_handles.len().try_into()?; - - let mut sampling_rates = RemoteArray::new(len); - let mut errors = RemoteArray::new(len); - - unsafe { - self.interface()?.GetItemSamplingRate( - len, - server_handles.as_ptr(), - sampling_rates.as_mut_ptr(), - errors.as_mut_ptr(), - )?; - } - - Ok((sampling_rates, errors)) - } - - /// Removes custom sampling rates for specified items. - /// - /// # Arguments - /// * `server_handles` - Array of server item handles - /// - /// # Returns - /// Array of per-item error codes - fn clear_item_sampling_rate( - &self, - server_handles: &[u32], - ) -> windows::core::Result> { - let len = server_handles.len().try_into()?; - - let mut errors = RemoteArray::new(len); - - unsafe { - self.interface()?.ClearItemSamplingRate( - len, - server_handles.as_ptr(), - errors.as_mut_ptr(), - )?; - } - - Ok(errors) - } - - /// Enables or disables data buffering for specified items. - /// - /// # Arguments - /// * `server_handles` - Array of server item handles - /// * `enable` - Array of boolean values to enable/disable buffering - /// - /// # Returns - /// Array of per-item error codes - /// - /// # Errors - /// Returns E_INVALIDARG if arrays have different lengths - fn set_item_buffer_enable( - &self, - server_handles: &[u32], - enable: &[bool], - ) -> windows::core::Result> { - if server_handles.len() != enable.len() { - return Err(windows::core::Error::new( - windows::Win32::Foundation::E_INVALIDARG, - "server_handles and enable must have the same length", - )); - } - - let len = server_handles.len().try_into()?; - - let mut errors = RemoteArray::new(len); - let enable_bool: Vec = enable.iter().map(|&v| BOOL::from(v)).collect(); - - unsafe { - self.interface()?.SetItemBufferEnable( - len, - server_handles.as_ptr(), - enable_bool.as_ptr(), - errors.as_mut_ptr(), - )?; - } - - Ok(errors) - } - - /// Gets current buffer enable states for specified items. - /// - /// # Arguments - /// * `server_handles` - Array of server item handles - /// - /// # Returns - /// Tuple containing: - /// - Array of current buffer enable states - /// - Array of per-item error codes - fn get_item_buffer_enable( - &self, - server_handles: &[u32], - ) -> windows::core::Result<( - RemoteArray, - RemoteArray, - )> { - let len = server_handles.len().try_into()?; - - let mut enable = RemoteArray::new(len); - let mut errors = RemoteArray::new(len); - - unsafe { - self.interface()?.GetItemBufferEnable( - len, - server_handles.as_ptr(), - enable.as_mut_ptr(), - errors.as_mut_ptr(), - )?; - } - - Ok((enable, errors)) - } -} diff --git a/opc_da/src/client/traits/mod.rs b/opc_da/src/client/traits/mod.rs deleted file mode 100644 index 9df27d5..0000000 --- a/opc_da/src/client/traits/mod.rs +++ /dev/null @@ -1,71 +0,0 @@ -/// OPC DA client trait definitions. -/// -/// This module contains all trait definitions for interacting with OPC DA servers. -/// The traits are organized by functionality and OPC DA version compatibility: -/// -/// Version independent traits: -/// - CommonTrait: Basic server configuration and error handling -/// - ConnectionPointContainerTrait: Event connection management -/// - DataObjectTrait: COM data transfer functionality -/// -/// OPC DA 1.0 traits: -/// - AsyncIoTrait: Basic asynchronous operations -/// - SyncIoTrait: Basic synchronous operations -/// -/// OPC DA 2.0 traits: -/// - AsyncIo2Trait: Enhanced asynchronous operations -/// - SyncIo2Trait: Enhanced synchronous operations -/// - BrowseServerAddressSpaceTrait: Address space navigation -/// -/// OPC DA 3.0 traits: -/// - AsyncIo3Trait: Advanced asynchronous operations -/// - BrowseTrait: Enhanced browsing capabilities -/// - ItemDeadbandMgtTrait: Item deadband management -/// - ItemIoTrait: Direct item access -/// - ItemSamplingMgtTrait: Sampling rate control -/// - GroupStateMgt2Trait: Extended group management -mod async_io; -mod async_io2; -mod async_io3; -mod browse; -mod browse_server_address_space; -mod client; -mod common; -mod connection_point_container; -mod data_callback; -mod data_object; -mod group_state_mgt; -mod group_state_mgt2; -mod item_deadband_mgt; -mod item_io; -mod item_mgt; -mod item_properties; -mod item_sampling_mgt; -mod public_group_state_mgt; -mod server; -mod server_public_groups; -mod sync_io; -mod sync_io2; - -pub use async_io::*; -pub use async_io2::*; -pub use async_io3::*; -pub use browse::*; -pub use browse_server_address_space::*; -pub use client::*; -pub use common::*; -pub use connection_point_container::*; -pub use data_callback::*; -pub use data_object::*; -pub use group_state_mgt::*; -pub use group_state_mgt2::*; -pub use item_deadband_mgt::*; -pub use item_io::*; -pub use item_mgt::*; -pub use item_properties::*; -pub use item_sampling_mgt::*; -pub use public_group_state_mgt::*; -pub use server::*; -pub use server_public_groups::*; -pub use sync_io::*; -pub use sync_io2::*; diff --git a/opc_da/src/client/traits/public_group_state_mgt.rs b/opc_da/src/client/traits/public_group_state_mgt.rs deleted file mode 100644 index 11e6c89..0000000 --- a/opc_da/src/client/traits/public_group_state_mgt.rs +++ /dev/null @@ -1,28 +0,0 @@ -/// Public group state management functionality. -/// -/// Provides methods to manage public groups in OPC servers. Public groups -/// can be shared between multiple clients, allowing for more efficient -/// server resource usage. -pub trait PublicGroupStateMgtTrait { - fn interface(&self) -> windows::core::Result<&opc_da_bindings::IOPCPublicGroupStateMgt>; - - /// Gets the public state of the group. - /// - /// # Returns - /// `true` if the group is public, `false` if it is private - fn get_state(&self) -> windows::core::Result { - unsafe { self.interface()?.GetState() }.map(|v| v.as_bool()) - } - - /// Converts a private group to a public group. - /// - /// # Returns - /// Ok(()) if the group was successfully converted to public - /// - /// # Notes - /// Once a group becomes public, it remains public until the server - /// is shut down or the group is deleted. - fn move_to_public(&self) -> windows::core::Result<()> { - unsafe { self.interface()?.MoveToPublic() } - } -} diff --git a/opc_da/src/client/traits/server.rs b/opc_da/src/client/traits/server.rs deleted file mode 100644 index ddac630..0000000 --- a/opc_da/src/client/traits/server.rs +++ /dev/null @@ -1,134 +0,0 @@ -use windows::core::Interface as _; - -use crate::{ - client::{GroupIterator, StringIterator}, - utils::{LocalPointer, RemotePointer}, -}; - -/// OPC Server management functionality. -/// -/// Provides methods to create and manage groups within an OPC server, -/// as well as monitor server status and enumerate existing groups. -pub trait ServerTrait> { - fn interface(&self) -> windows::core::Result<&opc_da_bindings::IOPCServer>; - - /// Adds a new group to the OPC server. - /// - /// # Arguments - /// * `name` - Group name for identification - /// * `active` - Whether the group should initially be active - /// * `client_handle` - Client-assigned handle for the group - /// * `update_rate` - Requested update rate in milliseconds - /// * `locale_id` - Locale ID for text strings - /// * `time_bias` - Time zone bias in minutes from UTC - /// * `percent_deadband` - Percent change required to trigger updates - /// - /// # Returns - /// The newly created group object - /// - /// # Errors - /// Returns E_POINTER if group creation fails - #[allow(clippy::too_many_arguments)] - fn add_group( - &self, - name: &str, - active: bool, - client_handle: u32, - update_rate: u32, - locale_id: u32, - time_bias: i32, - percent_deadband: f32, - revised_percent_deadband: &mut u32, - server_handle: &mut u32, - ) -> windows::core::Result { - let mut group = None; - let group_name = LocalPointer::from(name); - let group_name = group_name.as_pcwstr(); - - unsafe { - self.interface()?.AddGroup( - group_name, - active, - update_rate, - client_handle, - &time_bias, - &percent_deadband, - locale_id, - server_handle, - revised_percent_deadband, - &opc_da_bindings::IOPCItemMgt::IID, - &mut group, - )?; - } - - match group { - None => Err(windows::core::Error::new( - windows::Win32::Foundation::E_POINTER, - "Failed to add group, returned null", - )), - Some(group) => group.cast::()?.try_into(), - } - } - - /// Gets the current server status. - /// - /// # Returns - /// Server status structure containing vendor info, time, state, - /// and group counts - fn get_status( - &self, - ) -> windows::core::Result> { - let status = unsafe { self.interface()?.GetStatus()? }; - Ok(RemotePointer::from_raw(status)) - } - - /// Removes a group from the server. - /// - /// # Arguments - /// * `server_handle` - Server's handle for the group - /// * `force` - If true, remove even if clients are connected - fn remove_group(&self, server_handle: u32, force: bool) -> windows::core::Result<()> { - unsafe { - self.interface()?.RemoveGroup(server_handle, force)?; - } - Ok(()) - } - - /// Creates an enumerator for groups. - /// - /// # Arguments - /// * `scope` - Scope of groups to enumerate (public, private, or all) - /// - /// # Returns - /// Enumerator interface for iterating through groups - fn create_group_enumerator( - &self, - scope: opc_da_bindings::tagOPCENUMSCOPE, - ) -> windows::core::Result> { - let enumerator = unsafe { - self.interface()? - .CreateGroupEnumerator(scope, &windows::Win32::System::Com::IEnumUnknown::IID)? - }; - - Ok(GroupIterator::new(enumerator.cast()?)) - } - - /// Creates an enumerator for group names. - /// - /// # Arguments - /// * `scope` - Scope of group names to enumerate (public, private, or all) - /// - /// # Returns - /// Enumerator interface for iterating through group names - fn create_group_name_enumerator( - &self, - scope: opc_da_bindings::tagOPCENUMSCOPE, - ) -> windows::core::Result { - let enumerator = unsafe { - self.interface()? - .CreateGroupEnumerator(scope, &windows::Win32::System::Com::IEnumString::IID)? - }; - - Ok(StringIterator::new(enumerator.cast()?)) - } -} diff --git a/opc_da/src/client/traits/server_public_groups.rs b/opc_da/src/client/traits/server_public_groups.rs deleted file mode 100644 index 5260630..0000000 --- a/opc_da/src/client/traits/server_public_groups.rs +++ /dev/null @@ -1,39 +0,0 @@ -use crate::utils::LocalPointer; - -/// Server public groups management functionality. -/// -/// Provides methods to access and manage public groups that can be shared -/// between multiple OPC clients for more efficient server resource usage. -pub trait ServerPublicGroupsTrait { - fn interface(&self) -> windows::core::Result<&opc_da_bindings::IOPCServerPublicGroups>; - - /// Gets a public group by its name. - /// - /// # Arguments - /// * `name` - Name of the public group to retrieve - /// * `id` - Interface ID for the requested group interface - /// - /// # Returns - /// The requested interface pointer for the public group - fn get_public_group_by_name( - &self, - name: &str, - id: &windows::core::GUID, - ) -> windows::core::Result { - let name = LocalPointer::from(name); - - unsafe { self.interface()?.GetPublicGroupByName(name.as_pcwstr(), id) } - } - - /// Removes a public group from the server. - /// - /// # Arguments - /// * `server_group` - Server handle of the group to remove - /// * `force` - If true, removes group even if clients are connected - /// - /// # Returns - /// Ok(()) if the group was successfully removed - fn remove_public_group(&self, server_group: u32, force: bool) -> windows::core::Result<()> { - unsafe { self.interface()?.RemovePublicGroup(server_group, force) } - } -} diff --git a/opc_da/src/client/traits/sync_io.rs b/opc_da/src/client/traits/sync_io.rs deleted file mode 100644 index 7c4e762..0000000 --- a/opc_da/src/client/traits/sync_io.rs +++ /dev/null @@ -1,102 +0,0 @@ -use crate::utils::RemoteArray; -use windows::Win32::System::Variant::VARIANT; - -/// Synchronous I/O functionality (OPC DA 1.0). -/// -/// Provides methods for basic synchronous read/write operations -/// with direct server communication. -pub trait SyncIoTrait { - fn interface(&self) -> windows::core::Result<&opc_da_bindings::IOPCSyncIO>; - - /// Reads values synchronously from items. - /// - /// # Arguments - /// * `source` - Whether to read from cache or device - /// * `server_handles` - Array of server item handles - /// - /// # Returns - /// Tuple containing: - /// - Array of item states (value, quality, timestamp) - /// - Array of per-item error codes - /// - /// # Errors - /// Returns E_INVALIDARG if server_handles is empty - fn read( - &self, - source: opc_da_bindings::tagOPCDATASOURCE, - server_handles: &[u32], - ) -> windows::core::Result<( - RemoteArray, - RemoteArray, - )> { - if server_handles.is_empty() { - return Err(windows::core::Error::new( - windows::Win32::Foundation::E_INVALIDARG, - "server_handles cannot be empty", - )); - } - - let len = server_handles.len().try_into()?; - - let mut item_values = RemoteArray::new(len); - let mut errors = RemoteArray::new(len); - - unsafe { - self.interface()?.Read( - source, - len, - server_handles.as_ptr(), - item_values.as_mut_ptr(), - errors.as_mut_ptr(), - )?; - } - - Ok((item_values, errors)) - } - - /// Writes values synchronously to items. - /// - /// # Arguments - /// * `server_handles` - Array of server item handles - /// * `values` - Array of values to write - /// - /// # Returns - /// Array of per-item error codes - /// - /// # Errors - /// Returns E_INVALIDARG if arrays are empty or have different lengths - fn write( - &self, - server_handles: &[u32], - values: &[VARIANT], - ) -> windows::core::Result> { - if server_handles.len() != values.len() { - return Err(windows::core::Error::new( - windows::Win32::Foundation::E_INVALIDARG, - "server_handles and values must have the same length", - )); - } - - if server_handles.is_empty() { - return Err(windows::core::Error::new( - windows::Win32::Foundation::E_INVALIDARG, - "server_handles cannot be empty", - )); - } - - let len = server_handles.len().try_into()?; - - let mut errors = RemoteArray::new(len); - - unsafe { - self.interface()?.Write( - len, - server_handles.as_ptr(), - values.as_ptr(), - errors.as_mut_ptr(), - )?; - } - - Ok(errors) - } -} diff --git a/opc_da/src/client/traits/sync_io2.rs b/opc_da/src/client/traits/sync_io2.rs deleted file mode 100644 index d96e02f..0000000 --- a/opc_da/src/client/traits/sync_io2.rs +++ /dev/null @@ -1,118 +0,0 @@ -use crate::utils::RemoteArray; -use windows::Win32::System::Variant::VARIANT; - -/// Synchronous I/O functionality (OPC DA 3.0). -/// -/// Provides enhanced synchronous read/write operations with support for -/// quality, timestamp, and maximum age constraints. -pub trait SyncIo2Trait { - fn interface(&self) -> windows::core::Result<&opc_da_bindings::IOPCSyncIO2>; - - /// Reads values with maximum age constraint. - /// - /// # Arguments - /// * `server_handles` - Array of server item handles - /// * `max_age` - Maximum age constraints for each item in milliseconds - /// - /// # Returns - /// Tuple containing: - /// - Array of item values - /// - Array of quality values - /// - Array of timestamps - /// - Array of per-item error codes - /// - /// # Errors - /// Returns E_INVALIDARG if arrays are empty or have different lengths - #[allow(clippy::type_complexity)] - fn read_max_age( - &self, - server_handles: &[u32], - max_age: &[u32], - ) -> windows::core::Result<( - RemoteArray, - RemoteArray, - RemoteArray, - RemoteArray, - )> { - if server_handles.len() != max_age.len() { - return Err(windows::core::Error::new( - windows::Win32::Foundation::E_INVALIDARG, - "server_handles and max_age must have the same length", - )); - } - - if server_handles.is_empty() { - return Err(windows::core::Error::new( - windows::Win32::Foundation::E_INVALIDARG, - "server_handles cannot be empty", - )); - } - - let len = server_handles.len().try_into()?; - - let mut values = RemoteArray::new(len); - let mut qualities = RemoteArray::new(len); - let mut timestamps = RemoteArray::new(len); - let mut errors = RemoteArray::new(len); - - unsafe { - self.interface()?.ReadMaxAge( - len, - server_handles.as_ptr(), - max_age.as_ptr(), - values.as_mut_ptr(), - qualities.as_mut_ptr(), - timestamps.as_mut_ptr(), - errors.as_mut_ptr(), - )?; - } - - Ok((values, qualities, timestamps, errors)) - } - - /// Writes values with quality and timestamp information. - /// - /// # Arguments - /// * `server_handles` - Array of server item handles - /// * `values` - Array of value-quality-timestamp structures - /// - /// # Returns - /// Array of per-item error codes - /// - /// # Errors - /// Returns E_INVALIDARG if arrays are empty or have different lengths - fn write_vqt( - &self, - server_handles: &[u32], - values: &[opc_da_bindings::tagOPCITEMVQT], - ) -> windows::core::Result> { - if server_handles.len() != values.len() { - return Err(windows::core::Error::new( - windows::Win32::Foundation::E_INVALIDARG, - "server_handles and values must have the same length", - )); - } - - if server_handles.is_empty() { - return Err(windows::core::Error::new( - windows::Win32::Foundation::E_INVALIDARG, - "server_handles cannot be empty", - )); - } - - let len = server_handles.len().try_into()?; - - let mut errors = RemoteArray::new(len); - - unsafe { - self.interface()?.WriteVQT( - len, - server_handles.as_ptr(), - values.as_ptr(), - errors.as_mut_ptr(), - )?; - } - - Ok(errors) - } -} diff --git a/opc_da/src/client/unified/actor/client.rs b/opc_da/src/client/unified/actor/client.rs deleted file mode 100644 index d8f6f37..0000000 --- a/opc_da/src/client/unified/actor/client.rs +++ /dev/null @@ -1,65 +0,0 @@ -use actix::prelude::*; - -use crate::{ - client::{unified::Client, GuidIterator}, - mb_error, - utils::RemotePointer, -}; - -impl Actor for Client { - type Context = Context; -} - -impl Actor for GuidIterator { - type Context = Context; -} - -pub struct ClientActor(Addr); - -impl ClientActor { - pub fn new(client: Client) -> windows::core::Result { - Ok(Self(client.start())) - } -} - -// deref to the inner Addr -impl std::ops::Deref for ClientActor { - type Target = Addr; - - fn deref(&self) -> &Self::Target { - &self.0 - } -} - -#[derive(Message)] -#[rtype(result = "windows::core::Result>")] -struct GetServerGuids; - -impl ClientActor { - pub async fn get_servers(&self) -> windows::core::Result> { - mb_error!(self.send(GetServerGuids).await) - } -} - -impl Handler for Client { - type Result = windows::core::Result>; - - fn handle(&mut self, _: GetServerGuids, _: &mut Self::Context) -> Self::Result { - self.get_servers()? - .map(|r| match r { - Ok(guid) => { - let name = unsafe { - windows::Win32::System::Com::ProgIDFromCLSID(&guid).map_err(|e| { - windows::core::Error::new(e.code(), "Failed to get ProgID") - }) - }?; - - let name = RemotePointer::from(name); - - Ok((guid, name.try_into()?)) - } - Err(e) => Err(e), - }) - .collect() - } -} diff --git a/opc_da/src/client/unified/actor/mod.rs b/opc_da/src/client/unified/actor/mod.rs deleted file mode 100644 index fcd7ec0..0000000 --- a/opc_da/src/client/unified/actor/mod.rs +++ /dev/null @@ -1,23 +0,0 @@ -mod client; -mod runtime; -mod server; - -#[cfg(test)] -mod tests; - -pub use client::*; -pub use runtime::*; - -fn mb_error(err: actix::MailboxError) -> windows::core::Error { - windows::core::Error::new( - windows::Win32::Foundation::E_FAIL, - format!("Failed to send message to client actor: {err:?}"), - ) -} - -#[macro_export] -macro_rules! mb_error { - ($err:expr) => { - $err.map_err($crate::client::unified::actor::mb_error)? - }; -} diff --git a/opc_da/src/client/unified/actor/runtime.rs b/opc_da/src/client/unified/actor/runtime.rs deleted file mode 100644 index 8045fbe..0000000 --- a/opc_da/src/client/unified/actor/runtime.rs +++ /dev/null @@ -1,13 +0,0 @@ -use crate::client::unified::Guard; - -pub fn try_create_runtime() -> std::io::Result { - tokio::runtime::Builder::new_multi_thread() - .enable_all() - .on_thread_start(Guard::<()>::initialize) - .on_thread_stop(Guard::<()>::uninitialize) - .build() -} - -pub fn create_runtime() -> tokio::runtime::Runtime { - try_create_runtime().expect("Failed to create runtime") -} diff --git a/opc_da/src/client/unified/actor/server.rs b/opc_da/src/client/unified/actor/server.rs deleted file mode 100644 index 72fc8df..0000000 --- a/opc_da/src/client/unified/actor/server.rs +++ /dev/null @@ -1,7 +0,0 @@ -use actix::prelude::*; - -use crate::client::unified::Server; - -impl Actor for Server { - type Context = SyncContext; -} diff --git a/opc_da/src/client/unified/actor/tests.rs b/opc_da/src/client/unified/actor/tests.rs deleted file mode 100644 index 09e0c0f..0000000 --- a/opc_da/src/client/unified/actor/tests.rs +++ /dev/null @@ -1,13 +0,0 @@ -use crate::client::unified::{create_runtime, Client}; - -use super::ClientActor; - -#[test] -fn test_actor() { - actix::System::with_tokio_rt(create_runtime).block_on(async { - let client = ClientActor::new(Client::v2()).expect("Failed to create client actor"); - let servers = client.get_servers().await.expect("Failed to get servers"); - - assert!(!servers.is_empty()); - }); -} diff --git a/opc_da/src/client/unified/client.rs b/opc_da/src/client/unified/client.rs deleted file mode 100644 index 334c665..0000000 --- a/opc_da/src/client/unified/client.rs +++ /dev/null @@ -1,67 +0,0 @@ -use crate::{ - client::{v1, v2, v3, ClientTrait as _, GuidIterator}, - def::ClassContext, -}; - -use super::Server; - -#[derive(Debug)] -pub enum Client { - V1(v1::Client), - V2(v2::Client), - V3(v3::Client), -} - -impl Client { - pub fn v1() -> Self { - Self::V1(v1::Client) - } - - pub fn v2() -> Self { - Self::V2(v2::Client) - } - - pub fn v3() -> Self { - Self::V3(v3::Client) - } - - pub fn get_servers(&self) -> windows::core::Result { - match self { - Client::V1(client) => client.get_servers(), - Client::V2(client) => client.get_servers(), - Client::V3(client) => client.get_servers(), - } - } - - pub fn create_server(&self, class_id: windows::core::GUID) -> windows::core::Result { - match self { - Client::V1(client) => Ok(Server::V1( - client.create_server(class_id, ClassContext::All)?, - )), - Client::V2(client) => Ok(Server::V2( - client.create_server(class_id, ClassContext::All)?, - )), - Client::V3(client) => Ok(Server::V3( - client.create_server(class_id, ClassContext::All)?, - )), - } - } -} - -impl From for Client { - fn from(client: v1::Client) -> Self { - Self::V1(client) - } -} - -impl From for Client { - fn from(client: v2::Client) -> Self { - Self::V2(client) - } -} - -impl From for Client { - fn from(client: v3::Client) -> Self { - Self::V3(client) - } -} diff --git a/opc_da/src/client/unified/group.rs b/opc_da/src/client/unified/group.rs deleted file mode 100644 index 7ab42a1..0000000 --- a/opc_da/src/client/unified/group.rs +++ /dev/null @@ -1,659 +0,0 @@ -use std::collections::{BTreeMap, HashMap}; - -use windows_core::{ComObjectInner as _, IUnknown, Interface}; - -use crate::{ - client::{ - v1, v2, v3, AsyncIo2Trait, AsyncIo3Trait, ConnectionPointContainerTrait, DataCallback, - DataCallbackTrait, ItemMgtTrait, SyncIo2Trait, SyncIoTrait, - }, - def::{ - CancelCompleteEvent, DataChangeEvent, DataSourceTarget, ItemDef, ItemPartialValue, - ItemResult, ItemState, ItemValue, ReadCompleteEvent, WriteCompleteEvent, - }, - utils::{IntoBridge as _, TryToLocal as _, TryToNative as _}, -}; - -pub struct Group { - inner: GroupInner, - items: HashMap, - next_transaction_id: std::sync::atomic::AtomicU32, - initialized: bool, - data_callback_cookie: Option, - data_change_broadcaster: tokio::sync::broadcast::Sender, - data_change_awaiters: - std::sync::Mutex>>, - read_complete_awaiters: - std::sync::Mutex>>, - write_complete_awaiters: - std::sync::Mutex>>, - cancel_complete_awaiters: - std::sync::Mutex>>, -} - -pub enum GroupInner { - V1(v1::Group), - V2(v2::Group), - V3(v3::Group), -} - -pub struct Item { - pub name: String, - pub server_handle: u32, - pub client_handle: u32, -} - -impl Group { - fn new(inner: GroupInner) -> Self { - let data_change_broadcaster = tokio::sync::broadcast::Sender::new(32); - - Self { - inner, - items: HashMap::new(), - next_transaction_id: std::sync::atomic::AtomicU32::new(1), - initialized: false, - data_callback_cookie: None, - data_change_broadcaster, - data_change_awaiters: std::sync::Mutex::new(BTreeMap::new()), - read_complete_awaiters: std::sync::Mutex::new(BTreeMap::new()), - write_complete_awaiters: std::sync::Mutex::new(BTreeMap::new()), - cancel_complete_awaiters: std::sync::Mutex::new(BTreeMap::new()), - } - } - - pub fn initialize(&mut self) -> windows::core::Result<()> { - if self.initialized { - return Ok(()); - } - - let connection_point = match &self.inner { - GroupInner::V1(_) => return Ok(()), - GroupInner::V2(group) => group.data_callback_connection_point()?, - GroupInner::V3(group) => group.data_callback_connection_point()?, - }; - - if self.data_callback_cookie.is_none() { - let callback = DataCallback(self); - self.data_callback_cookie = Some(unsafe { - connection_point.Advise( - &callback - .into_object() - .into_interface::() - .cast::()?, - ) - }?); - } - - self.initialized = true; - - Ok(()) - } - - pub fn data_change_receiver(&self) -> tokio::sync::broadcast::Receiver { - self.data_change_broadcaster.subscribe() - } - - fn handle_callback( - &self, - awaiters: &std::sync::Mutex>>, - transaction_id: u32, - event: T, - ) -> windows::core::Result<()> { - let mut awaiters = awaiters.lock().map_err(|_| { - windows_core::Error::new(windows::Win32::Foundation::E_FAIL, "lock poisoned") - })?; - - let awaiter = awaiters.remove(&transaction_id).ok_or_else(|| { - windows_core::Error::new(windows::Win32::Foundation::E_FAIL, "no awaiter found") - })?; - - awaiter.send(event).map_err(|_| { - windows_core::Error::new(windows::Win32::Foundation::E_FAIL, "event awaiter dropped") - }) - } - - fn next_receiver( - &self, - awaiters: &std::sync::Mutex>>, - ) -> windows::core::Result<(u32, tokio::sync::oneshot::Receiver)> { - let transaction_id = self - .next_transaction_id - .fetch_add(1, std::sync::atomic::Ordering::SeqCst); - - let (sender, receiver) = tokio::sync::oneshot::channel(); - - let mut awaiters = awaiters.lock().map_err(|_| { - windows_core::Error::new(windows::Win32::Foundation::E_FAIL, "lock poisoned") - })?; - - awaiters.insert(transaction_id, sender); - - Ok((transaction_id, receiver)) - } -} - -impl DataCallbackTrait for Group { - fn on_data_change(&self, event: DataChangeEvent) -> windows_core::Result<()> { - self.data_change_broadcaster - .send(event.clone()) - .map_err(|_| { - windows_core::Error::new( - windows::Win32::Foundation::E_FAIL, - "data change event receiver dropped", - ) - })?; - - self.handle_callback(&self.data_change_awaiters, event.transaction_id, event) - } - - fn on_read_complete(&self, event: ReadCompleteEvent) -> windows_core::Result<()> { - self.handle_callback(&self.read_complete_awaiters, event.transaction_id, event) - } - - fn on_write_complete(&self, event: WriteCompleteEvent) -> windows_core::Result<()> { - self.handle_callback(&self.write_complete_awaiters, event.transaction_id, event) - } - - fn on_cancel_complete(&self, event: CancelCompleteEvent) -> windows_core::Result<()> { - self.handle_callback(&self.cancel_complete_awaiters, event.transaction_id, event) - } -} - -impl Group { - #[inline(always)] - fn item_mgt(&self) -> &dyn ItemMgtTrait { - match &self.inner { - GroupInner::V1(group) => group, - GroupInner::V2(group) => group, - GroupInner::V3(group) => group, - } - } - - pub fn add( - &self, - items: Vec, - ) -> windows::core::Result>> { - let bridge = items.into_bridge(); - self.item_mgt() - .add_items(&bridge.try_to_native()?)? - .try_to_local() - } - - pub fn validate( - &self, - items: Vec, - blob_update: bool, - ) -> windows::core::Result>> { - let bridge = items.into_bridge(); - self.item_mgt() - .validate_items(&bridge.try_to_native()?, blob_update)? - .try_to_local() - } - - pub fn remove( - &self, - server_handles: Vec, - ) -> windows::core::Result>> { - self.item_mgt() - .remove_items(&server_handles)? - .try_to_local() - } - - // TODO set_active_state - // TODO set_client_handle - // TODO set_datatypes - // TODO create_enumerator - - fn read_sync1( - &self, - sync_io1: &T, - data_source: DataSourceTarget, - server_handles: &[u32], - ) -> windows::core::Result>> { - let results: Vec> = sync_io1 - .read(data_source.try_to_native()?, server_handles)? - .try_to_local()?; - - Ok(results - .into_iter() - .map(|r| { - r.map(|r| ItemValue { - value: r.data_value, - quality: r.quality, - timestamp: r.timestamp, - }) - }) - .collect()) - } - - fn read_sync2( - &self, - sync_io2: &T, - server_handles: &[u32], - max_ages: &[u32], - ) -> windows::core::Result>> { - sync_io2 - .read_max_age(server_handles, max_ages)? - .try_to_local() - } - - pub fn read_sync( - &self, - items_names: &[S], - data_source: DataSourceTarget, - ) -> windows::core::Result>> - where - S: AsRef, - { - let server_handles: Vec = items_names - .iter() - .map(|name| { - self.items - .get(name.as_ref()) - .map(|item| item.server_handle) - .ok_or_else(|| { - windows::core::Error::new( - windows::Win32::Foundation::E_INVALIDARG, - "item name not found", - ) - }) - }) - .collect::>()?; - - match &self.inner { - GroupInner::V1(group) => self.read_sync1(group, data_source, &server_handles), - GroupInner::V2(group) => self.read_sync1(group, data_source, &server_handles), - GroupInner::V3(group) => self.read_sync2( - group, - &server_handles, - &vec![data_source.max_age(); server_handles.len()], - ), - } - } - - fn read_async2( - &self, - async_io2: &T, - server_handles: &[u32], - ) -> windows::core::Result<( - DataCallbackFuture, - Vec>, - )> { - let (transaction_id, receiver) = self.next_receiver(&self.read_complete_awaiters)?; - - let (cancel_id, results) = async_io2.read(server_handles, transaction_id)?; - - Ok(( - DataCallbackFuture { - receiver: Box::pin(receiver), - transaction_id, - cancel_id, - }, - results.try_to_local()?, - )) - } - - fn read_async3( - &self, - async_io3: &T, - server_handles: &[u32], - max_ages: &[u32], - ) -> windows::core::Result<( - DataCallbackFuture, - Vec>, - )> { - let (transaction_id, receiver) = self.next_receiver(&self.read_complete_awaiters)?; - - let (cancel_id, results) = - async_io3.read_max_age(server_handles, max_ages, transaction_id)?; - - Ok(( - DataCallbackFuture { - receiver: Box::pin(receiver), - transaction_id, - cancel_id, - }, - results.try_to_local()?, - )) - } - - pub fn read_async>( - &self, - items_names: &[S], - data_source: DataSourceTarget, - ) -> windows::core::Result<( - DataCallbackFuture, - Vec>, - )> { - let server_handles: Vec = items_names - .iter() - .map(|name| { - self.items - .get(name.as_ref()) - .map(|item| item.server_handle) - .ok_or_else(|| { - windows::core::Error::new( - windows::Win32::Foundation::E_INVALIDARG, - "item name not found", - ) - }) - }) - .collect::>()?; - - match &self.inner { - GroupInner::V1(_) => Err(windows_core::Error::new( - windows::Win32::Foundation::E_NOTIMPL, - "read_async not implemented for v1", - )), - GroupInner::V2(group) => self.read_async2(group, &server_handles), - GroupInner::V3(group) => self.read_async3( - group, - &server_handles, - &vec![data_source.max_age(); server_handles.len()], - ), - } - } - - fn write_sync1( - &self, - sync_io1: &T, - server_handles: &[u32], - item_values: &[windows::Win32::System::Variant::VARIANT], - ) -> windows::core::Result>> { - let results: Vec> = sync_io1 - .write(server_handles, item_values)? - .try_to_local()?; - - Ok(results) - } - - fn write_sync2( - &self, - sync_io2: &T, - server_handles: &[u32], - item_values: &[opc_da_bindings::tagOPCITEMVQT], - ) -> windows::core::Result>> { - sync_io2 - .write_vqt(server_handles, item_values)? - .try_to_local() - } - - pub fn write_sync( - &self, - item_entities: &[(S, ItemPartialValue)], - ) -> windows::core::Result>> - where - S: AsRef, - { - let server_handles: Vec = item_entities - .iter() - .map(|(name, _)| { - self.items - .get(name.as_ref()) - .map(|item| item.server_handle) - .ok_or_else(|| { - windows::core::Error::new( - windows::Win32::Foundation::E_INVALIDARG, - "item name not found", - ) - }) - }) - .collect::>()?; - - let variants = item_entities.iter().map(|(_, value)| value.value.clone()); - - let item_values = item_entities.iter().map(|(_, value)| value.try_to_native()); - - match &self.inner { - GroupInner::V1(group) => { - self.write_sync1(group, &server_handles, &variants.collect::>()) - } - GroupInner::V2(group) => { - self.write_sync1(group, &server_handles, &variants.collect::>()) - } - GroupInner::V3(group) => self.write_sync2( - group, - &server_handles, - &item_values.collect::>>()?, - ), - } - } - - fn write_async2( - &self, - async_io2: &T, - server_handles: &[u32], - item_values: &[windows::Win32::System::Variant::VARIANT], - ) -> windows::core::Result<( - DataCallbackFuture, - Vec>, - )> { - let transaction_id = self - .next_transaction_id - .fetch_add(1, std::sync::atomic::Ordering::SeqCst); - - let (sender, receive) = tokio::sync::oneshot::channel(); - - let mut awaiters = self.write_complete_awaiters.lock().map_err(|_| { - windows_core::Error::new(windows::Win32::Foundation::E_FAIL, "lock poisoned") - })?; - - awaiters.insert(transaction_id, sender); - - let (cancel_id, results) = async_io2.write(server_handles, item_values, transaction_id)?; - - Ok(( - DataCallbackFuture { - receiver: Box::pin(receive), - transaction_id, - cancel_id, - }, - results.try_to_local()?, - )) - } - - fn write_async3( - &self, - async_io3: &T, - server_handles: &[u32], - item_values: &[opc_da_bindings::tagOPCITEMVQT], - ) -> windows::core::Result<( - DataCallbackFuture, - Vec>, - )> { - let (transaction_id, receiver) = self.next_receiver(&self.write_complete_awaiters)?; - - let (cancel_id, results) = - async_io3.write_vqt(server_handles, item_values, transaction_id)?; - - Ok(( - DataCallbackFuture { - receiver: Box::pin(receiver), - transaction_id, - cancel_id, - }, - results.try_to_local()?, - )) - } - - pub fn write_async( - &self, - item_entities: &[(S, ItemPartialValue)], - ) -> windows::core::Result<( - DataCallbackFuture, - Vec>, - )> - where - S: AsRef, - { - let server_handles: Vec = item_entities - .iter() - .map(|(name, _)| { - self.items - .get(name.as_ref()) - .map(|item| item.server_handle) - .ok_or_else(|| { - windows::core::Error::new( - windows::Win32::Foundation::E_INVALIDARG, - "item name not found", - ) - }) - }) - .collect::>()?; - - let variants = item_entities.iter().map(|(_, value)| value.value.clone()); - - let item_values = item_entities.iter().map(|(_, value)| value.try_to_native()); - - match &self.inner { - GroupInner::V1(_) => Err(windows_core::Error::new( - windows::Win32::Foundation::E_NOTIMPL, - "write_async not implemented for v1", - )), - GroupInner::V2(group) => { - self.write_async2(group, &server_handles, &variants.collect::>()) - } - GroupInner::V3(group) => self.write_async3( - group, - &server_handles, - &item_values.collect::>>()?, - ), - } - } - - fn cancel_async2( - &self, - async_io2: &T, - cancel_id: u32, - ) -> windows::core::Result> { - let (sender, receiver) = tokio::sync::oneshot::channel(); - - let mut awaiters = self.cancel_complete_awaiters.lock().map_err(|_| { - windows_core::Error::new(windows::Win32::Foundation::E_FAIL, "lock poisoned") - })?; - - awaiters.insert(cancel_id, sender); - - async_io2.cancel2(cancel_id)?; - - Ok(DataCallbackFuture { - receiver: Box::pin(receiver), - transaction_id: cancel_id, - cancel_id, - }) - } - - pub fn cancel_async( - &self, - cancel_id: u32, - ) -> windows::core::Result> { - match &self.inner { - GroupInner::V1(_) => Err(windows_core::Error::new( - windows::Win32::Foundation::E_NOTIMPL, - "cancel_async not implemented for v1", - )), - GroupInner::V2(group) => self.cancel_async2(group, cancel_id), - GroupInner::V3(group) => self.cancel_async2(group, cancel_id), - } - } - - fn refresh2_async( - &self, - async_io2: &T, - data_source: DataSourceTarget, - ) -> windows::core::Result> { - let (transaction_id, receiver) = self.next_receiver(&self.data_change_awaiters)?; - - let cancel_id = async_io2.refresh2(data_source.try_to_native()?, transaction_id)?; - - Ok(DataCallbackFuture { - receiver: Box::pin(receiver), - transaction_id, - cancel_id, - }) - } - - fn refresh3_async( - &self, - async_io3: &T, - data_source: DataSourceTarget, - ) -> windows::core::Result> { - let (transaction_id, receiver) = self.next_receiver(&self.data_change_awaiters)?; - - let cancel_id = async_io3.refresh_max_age(data_source.max_age(), transaction_id)?; - - Ok(DataCallbackFuture { - receiver: Box::pin(receiver), - transaction_id, - cancel_id, - }) - } - - pub fn refresh_async( - &self, - data_source: DataSourceTarget, - ) -> windows::core::Result> { - match &self.inner { - GroupInner::V1(_) => Err(windows::core::Error::new( - windows::Win32::Foundation::E_NOTIMPL, - "refresh not implemented for v1", - )), - GroupInner::V2(group) => self.refresh2_async(group, data_source), - GroupInner::V3(group) => self.refresh3_async(group, data_source), - } - } -} - -impl From for Group { - fn from(group: v1::Group) -> Self { - Self::new(GroupInner::V1(group)) - } -} - -impl From for Group { - fn from(group: v2::Group) -> Self { - Self::new(GroupInner::V2(group)) - } -} - -impl From for Group { - fn from(group: v3::Group) -> Self { - Self::new(GroupInner::V3(group)) - } -} - -pub struct DataCallbackFuture { - receiver: std::pin::Pin>>, - transaction_id: u32, - cancel_id: u32, -} - -impl DataCallbackFuture { - pub fn cancel_id(&self) -> u32 { - self.cancel_id - } - - pub fn transaction_id(&self) -> u32 { - self.transaction_id - } -} - -impl std::future::Future for DataCallbackFuture { - type Output = windows::core::Result; - - fn poll( - mut self: std::pin::Pin<&mut Self>, - cx: &mut std::task::Context<'_>, - ) -> std::task::Poll { - match self.receiver.as_mut().poll(cx) { - std::task::Poll::Ready(Ok(event)) => std::task::Poll::Ready(Ok(event)), - std::task::Poll::Ready(Err(_)) => { - std::task::Poll::Ready(Err(windows_core::Error::new( - windows::Win32::Foundation::E_FAIL, - "data change event receiver dropped", - ))) - } - std::task::Poll::Pending => std::task::Poll::Pending, - } - } -} diff --git a/opc_da/src/client/unified/guard.rs b/opc_da/src/client/unified/guard.rs deleted file mode 100644 index 8802aff..0000000 --- a/opc_da/src/client/unified/guard.rs +++ /dev/null @@ -1,96 +0,0 @@ -/// A RAII guard that manages COM initialization and uninitialization for a thread. -/// -/// This type ensures that COM is properly initialized when the guard is created and -/// properly uninitialized when the guard is dropped. It wraps an inner value of type `T` -/// and provides access to it through the `Deref` trait. -/// -/// # Thread Safety -/// The guard is intentionally not `Send` and not `Sync` to ensure COM operations -/// remain on the thread where they were initialized. -#[derive(Debug)] -pub struct Guard { - inner: T, - /// Marker to ensure `Client` is not `Send` and not `Sync`. - _marker: std::marker::PhantomData<*const ()>, -} - -impl Guard { - /// Creates a new guard that initializes COM and wraps the provided value. - /// - /// # Arguments - /// * `value` - The value to wrap in the guard - /// - /// # Returns - /// Returns a `Result` containing the guard if COM initialization succeeds. - /// - /// # Errors - /// Returns an error if COM initialization fails. - pub fn new(value: T) -> windows::core::Result { - let guard = Self { - inner: value, - _marker: std::marker::PhantomData, - }; - - Self::try_initialize()?; - - Ok(guard) - } -} - -/// Provides direct access to the wrapped value through reference. -impl std::ops::Deref for Guard { - type Target = T; - - fn deref(&self) -> &Self::Target { - &self.inner - } -} - -/// Ensures COM is uninitialized when the guard is dropped. -impl Drop for Guard { - fn drop(&mut self) { - Self::uninitialize(); - } -} - -impl Guard { - /// Ensures COM is initialized for the current thread. - /// - /// # Returns - /// Returns the HRESULT of the COM initialization. - /// - /// # Thread Safety - /// COM initialization is performed with COINIT_MULTITHREADED flag. - /// - /// # Note - /// Callers should check the returned HRESULT for initialization failures. - pub(crate) fn try_initialize() -> windows::core::Result<()> { - unsafe { - windows::Win32::System::Com::CoInitializeEx( - None, - windows::Win32::System::Com::COINIT_MULTITHREADED, - ) - } - .ok() - } - - /// Initializes COM for the current thread, panicking on failure. - /// - /// # Panics - /// Panics if COM initialization fails. - /// - /// # Thread Safety - /// COM initialization is performed with COINIT_MULTITHREADED flag. - pub(crate) fn initialize() { - Self::try_initialize().expect("Failed to initialize COM"); - } - - /// Uninitializes COM for the current thread. - /// - /// # Safety - /// This method should be called when the thread is shutting down - /// and no more COM calls will be made. - pub(crate) fn uninitialize() { - unsafe { windows::Win32::System::Com::CoUninitialize() }; - } -} diff --git a/opc_da/src/client/unified/mod.rs b/opc_da/src/client/unified/mod.rs deleted file mode 100644 index 3d5e476..0000000 --- a/opc_da/src/client/unified/mod.rs +++ /dev/null @@ -1,14 +0,0 @@ -pub mod actor; -pub mod client; -pub mod group; -pub mod guard; -pub mod server; - -pub use actor::*; -pub use client::*; -pub use group::*; -pub use guard::*; -pub use server::*; - -#[cfg(test)] -mod tests; diff --git a/opc_da/src/client/unified/server.rs b/opc_da/src/client/unified/server.rs deleted file mode 100644 index 23aa2b6..0000000 --- a/opc_da/src/client/unified/server.rs +++ /dev/null @@ -1,127 +0,0 @@ -use crate::{ - client::{v1, v2, v3, ServerTrait}, - def::{BrowseFilter, BrowseType, EnumScope, GroupState, ServerStatus}, - utils::{ToNative as _, TryToLocal}, -}; - -use super::Group; - -pub enum Server { - V1(v1::Server), - V2(v2::Server), - V3(v3::Server), -} - -impl Server { - fn add_group_with_server< - G: TryFrom, - T: ServerTrait, - >( - server: &T, - mut state: GroupState, - ) -> windows::core::Result { - server.add_group( - &state.name, - state.active, - state.client_handle, - state.update_rate, - state.locale_id, - state.time_bias, - state.percent_deadband, - &mut state.update_rate, - &mut state.server_handle, - ) - } - - pub fn add_group(&self, state: GroupState) -> windows::core::Result { - match self { - Self::V1(server) => Ok(Self::add_group_with_server(server, state)?.into()), - Self::V2(server) => Ok(Self::add_group_with_server(server, state)?.into()), - Self::V3(server) => Ok(Self::add_group_with_server(server, state)?.into()), - } - } - - pub fn get_status(&self) -> windows::core::Result { - let status = match self { - Self::V1(server) => server.get_status(), - Self::V2(server) => server.get_status(), - Self::V3(server) => server.get_status(), - }?; - - status.ok()?.try_to_local() - } - - pub fn remove_group(&self, server_handle: u32, force: bool) -> windows::core::Result<()> { - match self { - Self::V1(server) => server.remove_group(server_handle, force), - Self::V2(server) => server.remove_group(server_handle, force), - Self::V3(server) => server.remove_group(server_handle, force), - } - } - - pub fn create_group_enumerator( - &self, - scope: EnumScope, - ) -> windows::core::Result { - let scope = scope.to_native(); - - let iterator = match self { - Self::V1(server) => GroupIterator::V1(server.create_group_enumerator(scope)?), - Self::V2(server) => GroupIterator::V2(server.create_group_enumerator(scope)?), - Self::V3(server) => GroupIterator::V3(server.create_group_enumerator(scope)?), - }; - - Ok(iterator) - } -} - -impl From for Server { - fn from(server: v1::Server) -> Self { - Self::V1(server) - } -} - -impl From for Server { - fn from(server: v2::Server) -> Self { - Self::V2(server) - } -} - -impl From for Server { - fn from(server: v3::Server) -> Self { - Self::V3(server) - } -} - -pub enum GroupIterator { - V1(v1::GroupIterator), - V2(v2::GroupIterator), - V3(v3::GroupIterator), -} - -impl Iterator for GroupIterator { - type Item = windows::core::Result; - - fn next(&mut self) -> Option { - match self { - Self::V1(iterator) => iterator.next().map(|group| group.map(Group::from)), - Self::V2(iterator) => iterator.next().map(|group| group.map(Group::from)), - Self::V3(iterator) => iterator.next().map(|group| group.map(Group::from)), - } - } -} - -pub struct BrowseItemsOptions { - pub browse_type: BrowseType, - pub browse_filter: BrowseFilter, - pub item_id: Option, - pub continuation_point: Option, - pub data_type_filter: u16, - pub access_rights_filter: u32, - pub max_elements: u32, - pub element_name_filter: Option, - pub vendor_filter: Option, - pub return_all_properties: bool, - pub return_property_values: bool, - pub property_ids: Vec, -} diff --git a/opc_da/src/client/unified/tests.rs b/opc_da/src/client/unified/tests.rs deleted file mode 100644 index 35ef1a8..0000000 --- a/opc_da/src/client/unified/tests.rs +++ /dev/null @@ -1,20 +0,0 @@ -use crate::def::*; - -use super::*; - -#[test] -fn test_unified() { - let client = Guard::new(Client::v2()).expect("Failed to create client guard"); - let mut servers = client.get_servers().expect("Failed to get servers"); - let server_id = servers - .next() - .expect("No servers found") - .expect("Failed to get server id"); - - let server = client - .create_server(server_id) - .expect("Failed to create server"); - - let group_state = GroupState::default(); - let _ = server.add_group(group_state).expect("Failed to add group"); -} diff --git a/opc_da/src/client/v1/mod.rs b/opc_da/src/client/v1/mod.rs deleted file mode 100644 index 177268d..0000000 --- a/opc_da/src/client/v1/mod.rs +++ /dev/null @@ -1,151 +0,0 @@ -//! OPC DA 1.0 server and group implementations. -//! -//! This module implements the original OPC DA 1.0 interfaces for servers and groups, -//! providing basic functionality for legacy systems. - -use windows::core::Interface as _; - -use super::{ - traits::{ - AsyncIoTrait, BrowseServerAddressSpaceTrait, DataObjectTrait, GroupStateMgtTrait, - ItemMgtTrait, PublicGroupStateMgtTrait, ServerPublicGroupsTrait, ServerTrait, SyncIoTrait, - }, - ClientTrait, -}; - -/// Client for OPC DA 1.0 servers. -#[derive(Debug)] -pub struct Client; - -impl ClientTrait for Client { - const CATALOG_ID: windows::core::GUID = opc_da_bindings::CATID_OPCDAServer10::IID; -} - -/// An OPC DA 1.0 server implementation. -/// -/// Provides access to OPC DA 1.0 server interfaces including: -/// - `IOPCServer` for basic server operations -/// - `IOPCServerPublicGroups` for public group management -/// - `IOPCBrowseServerAddressSpace` for browsing the address space -pub struct Server { - pub(crate) server: opc_da_bindings::IOPCServer, - pub(crate) server_public_groups: Option, - pub(crate) browse_server_address_space: Option, -} - -impl TryFrom for Server { - type Error = windows::core::Error; - - fn try_from(value: windows::core::IUnknown) -> windows::core::Result { - Ok(Self { - server: value.cast()?, - server_public_groups: value.cast().ok(), - browse_server_address_space: value.cast().ok(), - }) - } -} - -impl ServerTrait for Server { - fn interface(&self) -> windows::core::Result<&opc_da_bindings::IOPCServer> { - Ok(&self.server) - } -} - -impl ServerPublicGroupsTrait for Server { - fn interface(&self) -> windows::core::Result<&opc_da_bindings::IOPCServerPublicGroups> { - self.server_public_groups.as_ref().ok_or_else(|| { - windows::core::Error::new( - windows::Win32::Foundation::E_NOTIMPL, - "IOPCServerPublicGroups not supported", - ) - }) - } -} - -impl BrowseServerAddressSpaceTrait for Server { - fn interface(&self) -> windows::core::Result<&opc_da_bindings::IOPCBrowseServerAddressSpace> { - self.browse_server_address_space.as_ref().ok_or_else(|| { - windows::core::Error::new( - windows::Win32::Foundation::E_NOTIMPL, - "IOPCBrowseServerAddressSpace not supported", - ) - }) - } -} - -/// Iterator over OPC DA 1.0 groups. -pub type GroupIterator = super::GroupIterator; - -/// An OPC DA 1.0 group implementation. -/// -/// Provides access to OPC DA 1.0 group interfaces including: -/// - `IOPCItemMgt` for item management -/// - `IOPCGroupStateMgt` for group state management -/// - `IOPCPublicGroupStateMgt` for public group operations -/// - `IOPCSyncIO` for synchronous operations -/// - `IOPCAsyncIO` for asynchronous operations -/// - `IDataObject` for data transfer -pub struct Group { - pub(crate) item_mgt: opc_da_bindings::IOPCItemMgt, - pub(crate) group_state_mgt: opc_da_bindings::IOPCGroupStateMgt, - pub(crate) public_group_state_mgt: Option, - pub(crate) sync_io: opc_da_bindings::IOPCSyncIO, - pub(crate) async_io: opc_da_bindings::IOPCAsyncIO, - pub(crate) data_object: windows::Win32::System::Com::IDataObject, -} - -impl TryFrom for Group { - type Error = windows::core::Error; - - fn try_from(value: windows::core::IUnknown) -> windows::core::Result { - Ok(Self { - item_mgt: value.cast()?, - group_state_mgt: value.cast()?, - public_group_state_mgt: value.cast().ok(), - sync_io: value.cast()?, - async_io: value.cast()?, - data_object: value.cast()?, - }) - } -} - -impl ItemMgtTrait for Group { - fn interface(&self) -> windows::core::Result<&opc_da_bindings::IOPCItemMgt> { - Ok(&self.item_mgt) - } -} - -impl GroupStateMgtTrait for Group { - fn interface(&self) -> windows::core::Result<&opc_da_bindings::IOPCGroupStateMgt> { - Ok(&self.group_state_mgt) - } -} - -impl PublicGroupStateMgtTrait for Group { - fn interface(&self) -> windows::core::Result<&opc_da_bindings::IOPCPublicGroupStateMgt> { - self.public_group_state_mgt.as_ref().ok_or_else(|| { - windows::core::Error::new( - windows::Win32::Foundation::E_NOTIMPL, - "IOPCPublicGroupStateMgt not supported", - ) - }) - } -} - -impl SyncIoTrait for Group { - fn interface(&self) -> windows::core::Result<&opc_da_bindings::IOPCSyncIO> { - Ok(&self.sync_io) - } -} - -impl AsyncIoTrait for Group { - fn interface(&self) -> windows::core::Result<&opc_da_bindings::IOPCAsyncIO> { - Ok(&self.async_io) - } -} - -impl DataObjectTrait for Group { - fn interface(&self) -> windows::core::Result<&windows::Win32::System::Com::IDataObject> { - Ok(&self.data_object) - } -} diff --git a/opc_da/src/client/v2/mod.rs b/opc_da/src/client/v2/mod.rs deleted file mode 100644 index 46411fe..0000000 --- a/opc_da/src/client/v2/mod.rs +++ /dev/null @@ -1,209 +0,0 @@ -//! OPC DA 2.0 server and group implementations. -//! -//! This module implements the OPC DA 2.0 interfaces for servers and groups, -//! providing compatibility with the 2.0 version of the specification. - -use windows::core::Interface as _; - -use super::{ - ClientTrait, - traits::{ - AsyncIo2Trait, AsyncIoTrait, BrowseServerAddressSpaceTrait, CommonTrait, - ConnectionPointContainerTrait, DataObjectTrait, GroupStateMgtTrait, ItemMgtTrait, - ItemPropertiesTrait, PublicGroupStateMgtTrait, ServerPublicGroupsTrait, ServerTrait, - SyncIoTrait, - }, -}; - -/// Client for OPC DA 2.0 servers. -#[derive(Debug)] -pub struct Client; - -impl ClientTrait for Client { - const CATALOG_ID: windows::core::GUID = opc_da_bindings::CATID_OPCDAServer20::IID; -} - -/// An OPC DA 2.0 server implementation. -/// -/// Provides access to OPC DA 2.0 server interfaces including: -/// - `IOPCServer` for basic server operations -/// - `IOPCCommon` for server status and locale management -/// - `IOPCItemProperties` for browsing item properties -/// - `IOPCServerPublicGroups` for public group management -/// - `IOPCBrowseServerAddressSpace` for browsing the address space -pub struct Server { - pub(crate) server: opc_da_bindings::IOPCServer, - pub(crate) common: opc_comn_bindings::IOPCCommon, - pub(crate) connection_point_container: windows::Win32::System::Com::IConnectionPointContainer, - pub(crate) item_properties: opc_da_bindings::IOPCItemProperties, - pub(crate) server_public_groups: Option, - pub(crate) browse_server_address_space: Option, -} - -impl TryFrom for Server { - type Error = windows::core::Error; - - fn try_from(value: windows::core::IUnknown) -> windows::core::Result { - Ok(Self { - server: value.cast()?, - common: value.cast()?, - connection_point_container: value.cast()?, - item_properties: value.cast()?, - server_public_groups: value.cast().ok(), - browse_server_address_space: value.cast().ok(), - }) - } -} - -impl ServerTrait for Server { - fn interface(&self) -> windows::core::Result<&opc_da_bindings::IOPCServer> { - Ok(&self.server) - } -} - -impl CommonTrait for Server { - fn interface(&self) -> windows::core::Result<&opc_comn_bindings::IOPCCommon> { - Ok(&self.common) - } -} - -impl ConnectionPointContainerTrait for Server { - fn interface( - &self, - ) -> windows::core::Result<&windows::Win32::System::Com::IConnectionPointContainer> { - Ok(&self.connection_point_container) - } -} - -impl ItemPropertiesTrait for Server { - fn interface(&self) -> windows::core::Result<&opc_da_bindings::IOPCItemProperties> { - Ok(&self.item_properties) - } -} - -impl ServerPublicGroupsTrait for Server { - fn interface(&self) -> windows::core::Result<&opc_da_bindings::IOPCServerPublicGroups> { - self.server_public_groups.as_ref().ok_or_else(|| { - windows::core::Error::new( - windows::Win32::Foundation::E_NOTIMPL, - "IOPCServerPublicGroups not supported", - ) - }) - } -} - -impl BrowseServerAddressSpaceTrait for Server { - fn interface(&self) -> windows::core::Result<&opc_da_bindings::IOPCBrowseServerAddressSpace> { - self.browse_server_address_space.as_ref().ok_or_else(|| { - windows::core::Error::new( - windows::Win32::Foundation::E_NOTIMPL, - "IOPCBrowseServerAddressSpace not supported", - ) - }) - } -} - -/// Iterator over OPC DA 2.0 groups. -pub type GroupIterator = super::GroupIterator; - -/// An OPC DA 2.0 group implementation. -/// -/// Provides access to OPC DA 2.0 group interfaces including: -/// - `IOPCItemMgt` for item management -/// - `IOPCGroupStateMgt` for group state management -/// - `IOPCPublicGroupStateMgt` for public group operations -/// - `IOPCSyncIO` for synchronous operations -/// - `IOPCAsyncIO` and `IOPCAsyncIO2` for asynchronous operations -/// - `IDataObject` for data transfer -pub struct Group { - pub(crate) item_mgt: opc_da_bindings::IOPCItemMgt, - pub(crate) group_state_mgt: opc_da_bindings::IOPCGroupStateMgt, - pub(crate) public_group_state_mgt: Option, - pub(crate) sync_io: opc_da_bindings::IOPCSyncIO, - pub(crate) async_io: Option, - pub(crate) async_io2: opc_da_bindings::IOPCAsyncIO2, - pub(crate) connection_point_container: windows::Win32::System::Com::IConnectionPointContainer, - pub(crate) data_object: Option, -} - -impl TryFrom for Group { - type Error = windows::core::Error; - - fn try_from(value: windows::core::IUnknown) -> windows::core::Result { - Ok(Self { - item_mgt: value.cast()?, - group_state_mgt: value.cast()?, - public_group_state_mgt: value.cast().ok(), - sync_io: value.cast()?, - async_io: value.cast().ok(), - async_io2: value.cast()?, - connection_point_container: value.cast()?, - data_object: value.cast().ok(), - }) - } -} - -impl ItemMgtTrait for Group { - fn interface(&self) -> windows::core::Result<&opc_da_bindings::IOPCItemMgt> { - Ok(&self.item_mgt) - } -} - -impl GroupStateMgtTrait for Group { - fn interface(&self) -> windows::core::Result<&opc_da_bindings::IOPCGroupStateMgt> { - Ok(&self.group_state_mgt) - } -} - -impl PublicGroupStateMgtTrait for Group { - fn interface(&self) -> windows::core::Result<&opc_da_bindings::IOPCPublicGroupStateMgt> { - self.public_group_state_mgt.as_ref().ok_or_else(|| { - windows::core::Error::new( - windows::Win32::Foundation::E_NOTIMPL, - "IOPCPublicGroupStateMgt not supported", - ) - }) - } -} - -impl SyncIoTrait for Group { - fn interface(&self) -> windows::core::Result<&opc_da_bindings::IOPCSyncIO> { - Ok(&self.sync_io) - } -} - -impl AsyncIoTrait for Group { - fn interface(&self) -> windows::core::Result<&opc_da_bindings::IOPCAsyncIO> { - self.async_io.as_ref().ok_or_else(|| { - windows::core::Error::new( - windows::Win32::Foundation::E_NOTIMPL, - "IOPCAsyncIO not supported", - ) - }) - } -} - -impl AsyncIo2Trait for Group { - fn interface(&self) -> windows::core::Result<&opc_da_bindings::IOPCAsyncIO2> { - Ok(&self.async_io2) - } -} - -impl ConnectionPointContainerTrait for Group { - fn interface( - &self, - ) -> windows::core::Result<&windows::Win32::System::Com::IConnectionPointContainer> { - Ok(&self.connection_point_container) - } -} - -impl DataObjectTrait for Group { - fn interface(&self) -> windows::core::Result<&windows::Win32::System::Com::IDataObject> { - self.data_object.as_ref().ok_or_else(|| { - windows::core::Error::new( - windows::Win32::Foundation::E_NOTIMPL, - "IDataObject not supported", - ) - }) - } -} diff --git a/opc_da/src/client/v3/mod.rs b/opc_da/src/client/v3/mod.rs deleted file mode 100644 index fa485a5..0000000 --- a/opc_da/src/client/v3/mod.rs +++ /dev/null @@ -1,196 +0,0 @@ -//! OPC DA 3.0 server and group implementations. -//! -//! This module implements the OPC DA 3.0 interfaces for servers and groups, -//! providing access to the latest features of the OPC DA specification. - -use windows::core::Interface as _; - -use super::{ - ClientTrait, - traits::{ - AsyncIo2Trait, AsyncIo3Trait, BrowseTrait, CommonTrait, ConnectionPointContainerTrait, - GroupStateMgt2Trait, GroupStateMgtTrait, ItemDeadbandMgtTrait, ItemIoTrait, ItemMgtTrait, - ItemSamplingMgtTrait, ServerTrait, SyncIo2Trait, SyncIoTrait, - }, -}; - -/// Client for OPC DA 3.0 servers. -#[derive(Debug)] -pub struct Client; - -impl ClientTrait for Client { - const CATALOG_ID: windows::core::GUID = opc_da_bindings::CATID_OPCDAServer30::IID; -} - -/// An OPC DA 3.0 server implementation. -/// -/// Provides access to OPC DA 3.0 server interfaces including: -/// - `IOPCServer` for basic server operations -/// - `IOPCCommon` for server status and locale management -/// - `IOPCBrowse` for browsing the server address space -/// - `IOPCItemIO` for direct item read/write operations -pub struct Server { - pub(crate) server: opc_da_bindings::IOPCServer, - pub(crate) common: opc_comn_bindings::IOPCCommon, - pub(crate) connection_point_container: windows::Win32::System::Com::IConnectionPointContainer, - pub(crate) browse: opc_da_bindings::IOPCBrowse, - pub(crate) item_io: opc_da_bindings::IOPCItemIO, -} - -impl TryFrom for Server { - type Error = windows::core::Error; - - fn try_from(value: windows::core::IUnknown) -> windows::core::Result { - Ok(Self { - server: value.cast()?, - common: value.cast()?, - connection_point_container: value.cast()?, - browse: value.cast()?, - item_io: value.cast()?, - }) - } -} - -impl ServerTrait for Server { - fn interface(&self) -> windows::core::Result<&opc_da_bindings::IOPCServer> { - Ok(&self.server) - } -} - -impl CommonTrait for Server { - fn interface(&self) -> windows::core::Result<&opc_comn_bindings::IOPCCommon> { - Ok(&self.common) - } -} - -impl ConnectionPointContainerTrait for Server { - fn interface( - &self, - ) -> windows::core::Result<&windows::Win32::System::Com::IConnectionPointContainer> { - Ok(&self.connection_point_container) - } -} - -impl BrowseTrait for Server { - fn interface(&self) -> windows::core::Result<&opc_da_bindings::IOPCBrowse> { - Ok(&self.browse) - } -} - -impl ItemIoTrait for Server { - fn interface(&self) -> windows::core::Result<&opc_da_bindings::IOPCItemIO> { - Ok(&self.item_io) - } -} - -/// Iterator over OPC DA 3.0 groups. -pub type GroupIterator = super::GroupIterator; - -/// An OPC DA 3.0 group implementation. -/// -/// Provides access to OPC DA 3.0 group interfaces including: -/// - `IOPCItemMgt` for item management -/// - `IOPCGroupStateMgt` and `IOPCGroupStateMgt2` for group state management -/// - `IOPCSyncIO` and `IOPCSyncIO2` for synchronous operations -/// - `IOPCAsyncIO2` and `IOPCAsyncIO3` for asynchronous operations -/// - `IOPCItemSamplingMgt` for item sampling control -/// - `IOPCItemDeadbandMgt` for deadband management -#[derive(Debug)] -pub struct Group { - pub(crate) item_mgt: opc_da_bindings::IOPCItemMgt, - pub(crate) group_state_mgt: opc_da_bindings::IOPCGroupStateMgt, - pub(crate) group_state_mgt2: opc_da_bindings::IOPCGroupStateMgt2, - pub(crate) sync_io: opc_da_bindings::IOPCSyncIO, - pub(crate) sync_io2: opc_da_bindings::IOPCSyncIO2, - pub(crate) async_io2: opc_da_bindings::IOPCAsyncIO2, - pub(crate) async_io3: opc_da_bindings::IOPCAsyncIO3, - pub(crate) item_sampling_mgt: Option, - pub(crate) item_deadband_mgt: opc_da_bindings::IOPCItemDeadbandMgt, - pub(crate) connection_point_container: windows::Win32::System::Com::IConnectionPointContainer, -} - -impl TryFrom for Group { - type Error = windows::core::Error; - - fn try_from(value: windows::core::IUnknown) -> windows::core::Result { - Ok(Self { - item_mgt: value.cast()?, - group_state_mgt: value.cast()?, - group_state_mgt2: value.cast()?, - sync_io: value.cast()?, - sync_io2: value.cast()?, - async_io2: value.cast()?, - async_io3: value.cast()?, - item_deadband_mgt: value.cast()?, - item_sampling_mgt: value.cast().ok(), - connection_point_container: value.cast()?, - }) - } -} - -impl ItemMgtTrait for Group { - fn interface(&self) -> windows::core::Result<&opc_da_bindings::IOPCItemMgt> { - Ok(&self.item_mgt) - } -} - -impl GroupStateMgtTrait for Group { - fn interface(&self) -> windows::core::Result<&opc_da_bindings::IOPCGroupStateMgt> { - Ok(&self.group_state_mgt) - } -} - -impl GroupStateMgt2Trait for Group { - fn interface(&self) -> windows::core::Result<&opc_da_bindings::IOPCGroupStateMgt2> { - Ok(&self.group_state_mgt2) - } -} - -impl SyncIoTrait for Group { - fn interface(&self) -> windows::core::Result<&opc_da_bindings::IOPCSyncIO> { - Ok(&self.sync_io) - } -} - -impl SyncIo2Trait for Group { - fn interface(&self) -> windows::core::Result<&opc_da_bindings::IOPCSyncIO2> { - Ok(&self.sync_io2) - } -} - -impl AsyncIo2Trait for Group { - fn interface(&self) -> windows::core::Result<&opc_da_bindings::IOPCAsyncIO2> { - Ok(&self.async_io2) - } -} - -impl AsyncIo3Trait for Group { - fn interface(&self) -> windows::core::Result<&opc_da_bindings::IOPCAsyncIO3> { - Ok(&self.async_io3) - } -} - -impl ItemDeadbandMgtTrait for Group { - fn interface(&self) -> windows::core::Result<&opc_da_bindings::IOPCItemDeadbandMgt> { - Ok(&self.item_deadband_mgt) - } -} - -impl ItemSamplingMgtTrait for Group { - fn interface(&self) -> windows::core::Result<&opc_da_bindings::IOPCItemSamplingMgt> { - self.item_sampling_mgt.as_ref().ok_or_else(|| { - windows::core::Error::new( - windows::Win32::Foundation::E_NOTIMPL, - "IOPCItemSamplingMgt not supported", - ) - }) - } -} - -impl ConnectionPointContainerTrait for Group { - fn interface( - &self, - ) -> windows::core::Result<&windows::Win32::System::Com::IConnectionPointContainer> { - Ok(&self.connection_point_container) - } -} diff --git a/opc_da/src/def.rs b/opc_da/src/def.rs deleted file mode 100644 index fcc8716..0000000 --- a/opc_da/src/def.rs +++ /dev/null @@ -1,752 +0,0 @@ -use crate::{ - try_from_native, - utils::{IntoBridge, LocalPointer, RemoteArray, ToNative, TryFromNative, TryToNative}, -}; - -#[derive(Debug, Clone, PartialEq)] -pub enum Version { - V1, - V2, - V3, -} - -#[derive(Debug, Clone, Default, PartialEq)] -pub struct GroupState { - pub update_rate: u32, - pub active: bool, - pub name: String, - pub time_bias: i32, - pub percent_deadband: f32, - pub locale_id: u32, - pub client_handle: u32, - pub server_handle: u32, -} - -#[derive(Debug, Clone, PartialEq)] -pub struct ServerStatus { - pub start_time: std::time::SystemTime, - pub current_time: std::time::SystemTime, - pub last_update_time: std::time::SystemTime, - pub server_state: ServerState, - pub group_count: u32, - pub band_width: u32, - pub major_version: u16, - pub minor_version: u16, - pub build_number: u16, - pub vendor_info: String, -} - -impl TryFromNative for ServerStatus { - fn try_from_native( - native: &opc_da_bindings::tagOPCSERVERSTATUS, - ) -> windows::core::Result { - Ok(Self { - start_time: try_from_native!(&native.ftStartTime), - current_time: try_from_native!(&native.ftCurrentTime), - last_update_time: try_from_native!(&native.ftLastUpdateTime), - server_state: try_from_native!(&native.dwServerState), - group_count: native.dwGroupCount, - band_width: native.dwBandWidth, - major_version: native.wMajorVersion, - minor_version: native.wMinorVersion, - build_number: native.wBuildNumber, - vendor_info: try_from_native!(&native.szVendorInfo), - }) - } -} - -#[derive(Debug, Clone, Default, PartialEq)] -pub struct ItemDef { - pub access_path: String, - pub item_id: String, - pub active: bool, - pub client_handle: u32, - pub data_type: u16, - pub blob: Vec, -} - -pub struct ItemDefBridge { - pub access_path: LocalPointer>, - pub item_id: LocalPointer>, - pub active: bool, - pub item_client_handle: u32, - pub requested_data_type: u16, - pub blob: LocalPointer>, -} - -impl IntoBridge for ItemDef { - fn into_bridge(self) -> ItemDefBridge { - ItemDefBridge { - access_path: LocalPointer::from(&self.access_path), - item_id: LocalPointer::from(&self.item_id), - active: self.active, - item_client_handle: self.client_handle, - requested_data_type: self.data_type, - blob: LocalPointer::new(Some(self.blob)), - } - } -} - -impl TryToNative for ItemDefBridge { - fn try_to_native(&self) -> windows::core::Result { - Ok(opc_da_bindings::tagOPCITEMDEF { - szAccessPath: self.access_path.as_pwstr(), - szItemID: self.item_id.as_pwstr(), - bActive: self.active.into(), - hClient: self.item_client_handle, - vtRequestedDataType: self.requested_data_type, - dwBlobSize: self.blob.len().try_into().map_err(|_| { - windows::core::Error::new( - windows::Win32::Foundation::E_INVALIDARG, - "Blob size exceeds u32 maximum value", - ) - })?, - pBlob: self.blob.as_array_ptr() as *mut _, - wReserved: 0, - }) - } -} - -#[derive(Debug, Clone, PartialEq)] -pub struct ItemResult { - pub server_handle: u32, - pub data_type: u16, - pub access_rights: u32, - pub blob: Vec, -} - -impl TryFromNative for ItemResult { - fn try_from_native(native: &opc_da_bindings::tagOPCITEMRESULT) -> windows::core::Result { - Ok(Self { - server_handle: native.hServer, - data_type: native.vtCanonicalDataType, - access_rights: native.dwAccessRights, - blob: RemoteArray::from_mut_ptr(native.pBlob, native.dwBlobSize) - .as_slice() - .to_vec(), - }) - } -} - -#[derive(Debug, Clone, PartialEq)] -pub enum ServerState { - Running, - Failed, - NoConfig, - Suspended, - Test, - CommunicationFault, -} - -impl TryFromNative for ServerState { - fn try_from_native(native: &opc_da_bindings::tagOPCSERVERSTATE) -> windows::core::Result { - match *native { - opc_da_bindings::OPC_STATUS_RUNNING => Ok(ServerState::Running), - opc_da_bindings::OPC_STATUS_FAILED => Ok(ServerState::Failed), - opc_da_bindings::OPC_STATUS_NOCONFIG => Ok(ServerState::NoConfig), - opc_da_bindings::OPC_STATUS_SUSPENDED => Ok(ServerState::Suspended), - opc_da_bindings::OPC_STATUS_TEST => Ok(ServerState::Test), - opc_da_bindings::OPC_STATUS_COMM_FAULT => Ok(ServerState::CommunicationFault), - unknown => Err(windows::core::Error::new( - windows::Win32::Foundation::E_INVALIDARG, - format!("Unknown server state: {unknown:?}"), - )), - } - } -} - -impl ToNative for ServerState { - fn to_native(&self) -> opc_da_bindings::tagOPCSERVERSTATE { - match self { - ServerState::Running => opc_da_bindings::OPC_STATUS_RUNNING, - ServerState::Failed => opc_da_bindings::OPC_STATUS_FAILED, - ServerState::NoConfig => opc_da_bindings::OPC_STATUS_NOCONFIG, - ServerState::Suspended => opc_da_bindings::OPC_STATUS_SUSPENDED, - ServerState::Test => opc_da_bindings::OPC_STATUS_TEST, - ServerState::CommunicationFault => opc_da_bindings::OPC_STATUS_COMM_FAULT, - } - } -} - -#[derive(Debug, Clone, PartialEq)] -pub enum EnumScope { - PrivateConnections, - PublicConnections, - AllConnections, - Public, - Private, - All, -} - -impl TryFromNative for EnumScope { - fn try_from_native(native: &opc_da_bindings::tagOPCENUMSCOPE) -> windows::core::Result { - match *native { - opc_da_bindings::OPC_ENUM_PRIVATE_CONNECTIONS => Ok(EnumScope::PrivateConnections), - opc_da_bindings::OPC_ENUM_PUBLIC_CONNECTIONS => Ok(EnumScope::PublicConnections), - opc_da_bindings::OPC_ENUM_ALL_CONNECTIONS => Ok(EnumScope::AllConnections), - opc_da_bindings::OPC_ENUM_PUBLIC => Ok(EnumScope::Public), - opc_da_bindings::OPC_ENUM_PRIVATE => Ok(EnumScope::Private), - opc_da_bindings::OPC_ENUM_ALL => Ok(EnumScope::All), - unknown => Err(windows::core::Error::new( - windows::Win32::Foundation::E_INVALIDARG, - format!("Unknown enum scope: {unknown:?}"), - )), - } - } -} - -impl ToNative for EnumScope { - fn to_native(&self) -> opc_da_bindings::tagOPCENUMSCOPE { - match self { - EnumScope::PrivateConnections => opc_da_bindings::OPC_ENUM_PRIVATE_CONNECTIONS, - EnumScope::PublicConnections => opc_da_bindings::OPC_ENUM_PUBLIC_CONNECTIONS, - EnumScope::AllConnections => opc_da_bindings::OPC_ENUM_ALL_CONNECTIONS, - EnumScope::Public => opc_da_bindings::OPC_ENUM_PUBLIC, - EnumScope::Private => opc_da_bindings::OPC_ENUM_PRIVATE, - EnumScope::All => opc_da_bindings::OPC_ENUM_ALL, - } - } -} - -pub struct ItemAttributes { - pub access_path: String, - pub item_id: String, - pub active: bool, - pub client_handle: u32, - pub server_handle: u32, - pub access_rights: u32, - pub blob: Vec, - pub requested_data_type: u16, - pub canonical_data_type: u16, - pub eu_type: EuType, - pub eu_info: windows::Win32::System::Variant::VARIANT, -} - -impl TryFromNative for ItemAttributes { - fn try_from_native( - native: &opc_da_bindings::tagOPCITEMATTRIBUTES, - ) -> windows::core::Result { - Ok(Self { - access_path: try_from_native!(&native.szAccessPath), - item_id: try_from_native!(&native.szItemID), - active: native.bActive.into(), - client_handle: native.hClient, - server_handle: native.hServer, - access_rights: native.dwAccessRights, - blob: RemoteArray::from_mut_ptr(native.pBlob, native.dwBlobSize) - .as_slice() - .to_vec(), - requested_data_type: native.vtRequestedDataType, - canonical_data_type: native.vtCanonicalDataType, - eu_type: try_from_native!(&native.dwEUType), - eu_info: native.vEUInfo.clone(), - }) - } -} - -pub enum EuType { - NoEnum, - Analog, - Enumerated, -} - -impl TryFromNative for EuType { - fn try_from_native(native: &opc_da_bindings::tagOPCEUTYPE) -> windows::core::Result { - match *native { - opc_da_bindings::OPC_NOENUM => Ok(EuType::NoEnum), - opc_da_bindings::OPC_ANALOG => Ok(EuType::Analog), - opc_da_bindings::OPC_ENUMERATED => Ok(EuType::Enumerated), - unknown => Err(windows::core::Error::new( - windows::Win32::Foundation::E_INVALIDARG, - format!("Unknown EU type: {unknown:?}"), - )), - } - } -} - -pub struct ItemState { - pub client_handle: u32, - pub timestamp: std::time::SystemTime, - pub quality: u16, - pub data_value: windows::Win32::System::Variant::VARIANT, -} - -impl TryFromNative for ItemState { - fn try_from_native(native: &opc_da_bindings::tagOPCITEMSTATE) -> windows::core::Result { - Ok(Self { - client_handle: native.hClient, - timestamp: try_from_native!(&native.ftTimeStamp), - quality: native.wQuality, - data_value: native.vDataValue.clone(), - }) - } -} - -pub enum DataSourceTarget { - ForceCache, - ForceDevice, - WithMaxAge(u32), -} - -impl DataSourceTarget { - pub fn max_age(&self) -> u32 { - match self { - DataSourceTarget::WithMaxAge(max_age) => *max_age, - DataSourceTarget::ForceCache => u32::MAX, - DataSourceTarget::ForceDevice => 0, - } - } -} - -impl TryFromNative for DataSourceTarget { - fn try_from_native(native: &opc_da_bindings::tagOPCDATASOURCE) -> windows::core::Result { - match *native { - opc_da_bindings::OPC_DS_CACHE => Ok(DataSourceTarget::ForceCache), - opc_da_bindings::OPC_DS_DEVICE => Ok(DataSourceTarget::ForceDevice), - unknown => Err(windows::core::Error::new( - windows::Win32::Foundation::E_INVALIDARG, - format!("Unknown data source: {unknown:?}"), - )), - } - } -} - -impl TryToNative for DataSourceTarget { - fn try_to_native(&self) -> windows::core::Result { - match self { - DataSourceTarget::ForceCache => Ok(opc_da_bindings::OPC_DS_CACHE), - DataSourceTarget::ForceDevice => Ok(opc_da_bindings::OPC_DS_DEVICE), - DataSourceTarget::WithMaxAge(_) => Err(windows::core::Error::new( - windows::Win32::Foundation::E_INVALIDARG, - "MaxAge data source requires a value", - )), - } - } -} - -pub struct ItemValue { - pub value: windows::Win32::System::Variant::VARIANT, - pub quality: u16, - pub timestamp: std::time::SystemTime, -} - -impl - TryFromNative<( - RemoteArray, - RemoteArray, - RemoteArray, - RemoteArray, - )> for Vec> -{ - fn try_from_native( - native: &( - RemoteArray, - RemoteArray, - RemoteArray, - RemoteArray, - ), - ) -> windows::core::Result { - let (values, qualities, timestamps, errors) = native; - - if values.len() != qualities.len() - || values.len() != timestamps.len() - || values.len() != errors.len() - { - return Err(windows::core::Error::new( - windows::Win32::Foundation::E_INVALIDARG, - "Arrays have different lengths", - )); - } - - Ok(values - .as_slice() - .iter() - .zip(qualities.as_slice()) - .zip(timestamps.as_slice()) - .zip(errors.as_slice()) - .map(|(((value, quality), timestamp), error)| { - if error.is_ok() { - Ok(ItemValue { - value: value.clone(), - quality: *quality, - timestamp: try_from_native!(timestamp), - }) - } else { - Err((*error).into()) - } - }) - .collect()) - } -} - -pub struct ItemPartialValue { - pub value: windows::Win32::System::Variant::VARIANT, - pub quality: Option, - pub timestamp: Option, -} - -// try to native -impl TryToNative for ItemPartialValue { - fn try_to_native(&self) -> windows::core::Result { - Ok(opc_da_bindings::tagOPCITEMVQT { - vDataValue: self.value.clone(), - bQualitySpecified: self.quality.is_some().into(), - wQuality: self.quality.unwrap_or_default(), - bTimeStampSpecified: self.timestamp.is_some().into(), - ftTimeStamp: self - .timestamp - .map(|t| t.try_to_native()) - .transpose()? - .unwrap_or_default(), - wReserved: 0, - dwReserved: 0, - }) - } -} - -pub enum BrowseType { - Branch, - Leaf, - Flat, -} - -impl TryFromNative for BrowseType { - fn try_from_native(native: &opc_da_bindings::tagOPCBROWSETYPE) -> windows::core::Result { - match *native { - opc_da_bindings::OPC_BRANCH => Ok(BrowseType::Branch), - opc_da_bindings::OPC_LEAF => Ok(BrowseType::Leaf), - opc_da_bindings::OPC_FLAT => Ok(BrowseType::Flat), - unknown => Err(windows::core::Error::new( - windows::Win32::Foundation::E_INVALIDARG, - format!("Unknown browse type: {unknown:?}"), - )), - } - } -} - -impl ToNative for BrowseType { - fn to_native(&self) -> opc_da_bindings::tagOPCBROWSETYPE { - match self { - BrowseType::Branch => opc_da_bindings::OPC_BRANCH, - BrowseType::Leaf => opc_da_bindings::OPC_LEAF, - BrowseType::Flat => opc_da_bindings::OPC_FLAT, - } - } -} - -pub enum BrowseFilter { - All, - Branches, - Items, -} - -impl TryFromNative for BrowseFilter { - fn try_from_native( - native: &opc_da_bindings::tagOPCBROWSEFILTER, - ) -> windows::core::Result { - match *native { - opc_da_bindings::OPC_BROWSE_FILTER_ALL => Ok(BrowseFilter::All), - opc_da_bindings::OPC_BROWSE_FILTER_BRANCHES => Ok(BrowseFilter::Branches), - opc_da_bindings::OPC_BROWSE_FILTER_ITEMS => Ok(BrowseFilter::Items), - unknown => Err(windows::core::Error::new( - windows::Win32::Foundation::E_INVALIDARG, - format!("Unknown browse filter: {unknown:?}"), - )), - } - } -} - -impl ToNative for BrowseFilter { - fn to_native(&self) -> opc_da_bindings::tagOPCBROWSEFILTER { - match self { - BrowseFilter::All => opc_da_bindings::OPC_BROWSE_FILTER_ALL, - BrowseFilter::Branches => opc_da_bindings::OPC_BROWSE_FILTER_BRANCHES, - BrowseFilter::Items => opc_da_bindings::OPC_BROWSE_FILTER_ITEMS, - } - } -} - -#[derive(Debug, Clone, PartialEq)] -pub enum DataCallbackEvent { - DataChange(DataChangeEvent), - ReadComplete(ReadCompleteEvent), - WriteComplete(WriteCompleteEvent), - CancelComplete(CancelCompleteEvent), -} - -#[derive(Debug, Clone, PartialEq)] -pub struct DataChangeEvent { - pub transaction_id: u32, - pub group_handle: u32, - pub master_quality: windows_core::HRESULT, - pub master_error: windows_core::HRESULT, - pub client_items: RemoteArray, - pub values: RemoteArray, - pub qualities: RemoteArray, - pub timestamps: RemoteArray, - pub errors: RemoteArray, -} - -#[derive(Debug, Clone, PartialEq)] -pub struct ReadCompleteEvent { - pub transaction_id: u32, - pub group_handle: u32, - pub master_quality: windows_core::HRESULT, - pub master_error: windows_core::HRESULT, - pub client_items: RemoteArray, - pub values: RemoteArray, - pub qualities: RemoteArray, - pub timestamps: RemoteArray, - pub errors: RemoteArray, -} - -#[derive(Debug, Clone, PartialEq)] -pub struct WriteCompleteEvent { - pub transaction_id: u32, - pub group_handle: u32, - pub master_error: windows_core::HRESULT, - pub client_handles: RemoteArray, - pub errors: RemoteArray, -} - -#[derive(Debug, Clone, PartialEq)] -pub struct CancelCompleteEvent { - pub transaction_id: u32, - pub group_handle: u32, -} - -pub enum NamespaceType { - Flat, - Hierarchy, -} - -impl TryFromNative for NamespaceType { - fn try_from_native( - native: &opc_da_bindings::tagOPCNAMESPACETYPE, - ) -> windows::core::Result { - match *native { - opc_da_bindings::OPC_NS_HIERARCHIAL => Ok(NamespaceType::Hierarchy), - opc_da_bindings::OPC_NS_FLAT => Ok(NamespaceType::Flat), - unknown => Err(windows::core::Error::new( - windows::Win32::Foundation::E_INVALIDARG, - format!("Unknown namespace type: {unknown:?}"), - )), - } - } -} - -impl ToNative for NamespaceType { - fn to_native(&self) -> opc_da_bindings::tagOPCNAMESPACETYPE { - match self { - NamespaceType::Hierarchy => opc_da_bindings::OPC_NS_HIERARCHIAL, - NamespaceType::Flat => opc_da_bindings::OPC_NS_FLAT, - } - } -} - -// COSERVERINFO -#[derive(Debug, Clone, PartialEq)] -pub struct ServerInfo { - pub name: String, - pub auth_info: AuthInfo, -} - -pub struct ServerInfoBridge { - pub name: LocalPointer>, - pub auth_info: AuthInfoBridge, -} - -impl IntoBridge for ServerInfo { - fn into_bridge(self) -> ServerInfoBridge { - ServerInfoBridge { - name: LocalPointer::from(&self.name), - auth_info: self.auth_info.into_bridge(), - } - } -} - -impl TryToNative for ServerInfoBridge { - fn try_to_native(&self) -> windows::core::Result { - Ok(windows::Win32::System::Com::COSERVERINFO { - dwReserved1: 0, - dwReserved2: 0, - pwszName: self.name.as_pwstr(), - pAuthInfo: &self.auth_info.try_to_native()? as *const _ as *mut _, - }) - } -} - -#[derive(Debug, Clone, PartialEq)] -pub struct AuthInfo { - pub authn_svc: u32, - pub authz_svc: u32, - pub server_principal_name: String, - pub authn_level: u32, - pub impersonation_level: u32, - pub auth_identity_data: AuthIdentity, - pub capabilities: u32, -} - -pub struct AuthInfoBridge { - pub authn_svc: u32, - pub authz_svc: u32, - pub server_principal_name: LocalPointer>, - pub authn_level: u32, - pub impersonation_level: u32, - pub auth_identity_data: AuthIdentityBridge, - pub capabilities: u32, -} - -impl IntoBridge for AuthInfo { - fn into_bridge(self) -> AuthInfoBridge { - AuthInfoBridge { - authn_svc: self.authn_svc, - authz_svc: self.authz_svc, - server_principal_name: LocalPointer::from(&self.server_principal_name), - authn_level: self.authn_level, - impersonation_level: self.impersonation_level, - auth_identity_data: self.auth_identity_data.into_bridge(), - capabilities: self.capabilities, - } - } -} - -impl TryToNative for AuthInfoBridge { - fn try_to_native(&self) -> windows::core::Result { - Ok(windows::Win32::System::Com::COAUTHINFO { - dwAuthnSvc: self.authn_svc, - dwAuthzSvc: self.authz_svc, - pwszServerPrincName: self.server_principal_name.as_pwstr(), - dwAuthnLevel: self.authn_level, - dwImpersonationLevel: self.impersonation_level, - pAuthIdentityData: &self.auth_identity_data.try_to_native()? as *const _ as *mut _, - dwCapabilities: self.capabilities, - }) - } -} - -#[derive(Debug, Clone, PartialEq)] -pub struct AuthIdentity { - pub user: String, - pub domain: String, - pub password: String, - pub flags: u32, -} - -pub struct AuthIdentityBridge { - pub user: LocalPointer>, - pub domain: LocalPointer>, - pub password: LocalPointer>, - pub flags: u32, -} - -impl IntoBridge for AuthIdentity { - fn into_bridge(self) -> AuthIdentityBridge { - AuthIdentityBridge { - user: LocalPointer::from(&self.user), - domain: LocalPointer::from(&self.domain), - password: LocalPointer::from(&self.password), - flags: self.flags, - } - } -} - -impl TryToNative for AuthIdentityBridge { - fn try_to_native(&self) -> windows::core::Result { - Ok(windows::Win32::System::Com::COAUTHIDENTITY { - User: self.user.as_pwstr().0, - UserLength: self.user.len().try_into().map_err(|_| { - windows::core::Error::new( - windows::Win32::Foundation::E_INVALIDARG, - "User name exceeds u32 maximum length", - ) - })?, - Domain: self.domain.as_pwstr().0, - DomainLength: self.domain.len().try_into().map_err(|_| { - windows::core::Error::new( - windows::Win32::Foundation::E_INVALIDARG, - "Domain name exceeds u32 maximum length", - ) - })?, - Password: self.password.as_pwstr().0, - PasswordLength: self.password.len().try_into().map_err(|_| { - windows::core::Error::new( - windows::Win32::Foundation::E_INVALIDARG, - "Password exceeds u32 maximum length", - ) - })?, - Flags: self.flags, - }) - } -} - -#[derive(Debug, Clone, PartialEq)] -pub enum ClassContext { - All, - InProcServer, - InProcHandler, - LocalServer, - InProcServer16, - RemoteServer, - InProcHandler16, - NoCodeDownload, - NoCustomMarshal, - EnableCodeDownload, - NoFailureLog, - DisableAAA, - EnableAAA, - FromDefaultContext, - ActivateX86Server, - Activate32BitServer, - Activate64BitServer, - EnableCloaking, - AppContainer, - ActivateAAAAsIU, - ActivateARM32Server, - AllowLowerTrustRegistration, - PsDll, -} - -impl ToNative for ClassContext { - fn to_native(&self) -> windows::Win32::System::Com::CLSCTX { - match self { - ClassContext::All => windows::Win32::System::Com::CLSCTX_ALL, - ClassContext::InProcServer => windows::Win32::System::Com::CLSCTX_INPROC_SERVER, - ClassContext::InProcHandler => windows::Win32::System::Com::CLSCTX_INPROC_HANDLER, - ClassContext::LocalServer => windows::Win32::System::Com::CLSCTX_LOCAL_SERVER, - ClassContext::InProcServer16 => windows::Win32::System::Com::CLSCTX_INPROC_SERVER16, - ClassContext::RemoteServer => windows::Win32::System::Com::CLSCTX_REMOTE_SERVER, - ClassContext::InProcHandler16 => windows::Win32::System::Com::CLSCTX_INPROC_HANDLER16, - ClassContext::NoCodeDownload => windows::Win32::System::Com::CLSCTX_NO_CODE_DOWNLOAD, - ClassContext::NoCustomMarshal => windows::Win32::System::Com::CLSCTX_NO_CUSTOM_MARSHAL, - ClassContext::EnableCodeDownload => { - windows::Win32::System::Com::CLSCTX_ENABLE_CODE_DOWNLOAD - } - ClassContext::NoFailureLog => windows::Win32::System::Com::CLSCTX_NO_FAILURE_LOG, - ClassContext::DisableAAA => windows::Win32::System::Com::CLSCTX_DISABLE_AAA, - ClassContext::EnableAAA => windows::Win32::System::Com::CLSCTX_ENABLE_AAA, - ClassContext::FromDefaultContext => { - windows::Win32::System::Com::CLSCTX_FROM_DEFAULT_CONTEXT - } - ClassContext::ActivateX86Server => { - windows::Win32::System::Com::CLSCTX_ACTIVATE_X86_SERVER - } - ClassContext::Activate32BitServer => { - windows::Win32::System::Com::CLSCTX_ACTIVATE_32_BIT_SERVER - } - ClassContext::Activate64BitServer => { - windows::Win32::System::Com::CLSCTX_ACTIVATE_64_BIT_SERVER - } - ClassContext::EnableCloaking => windows::Win32::System::Com::CLSCTX_ENABLE_CLOAKING, - ClassContext::AppContainer => windows::Win32::System::Com::CLSCTX_APPCONTAINER, - ClassContext::ActivateAAAAsIU => windows::Win32::System::Com::CLSCTX_ACTIVATE_AAA_AS_IU, - ClassContext::ActivateARM32Server => { - windows::Win32::System::Com::CLSCTX_ACTIVATE_ARM32_SERVER - } - ClassContext::AllowLowerTrustRegistration => { - windows::Win32::System::Com::CLSCTX_ALLOW_LOWER_TRUST_REGISTRATION - } - ClassContext::PsDll => windows::Win32::System::Com::CLSCTX_PS_DLL, - } - } -} diff --git a/opc_da/src/lib.rs b/opc_da/src/lib.rs index 930930e..8b13789 100644 --- a/opc_da/src/lib.rs +++ b/opc_da/src/lib.rs @@ -1,7 +1 @@ -pub mod def; -pub mod utils; -#[cfg(feature = "unstable_client")] -pub mod client; -#[cfg(feature = "unstable_server")] -pub mod server; diff --git a/opc_da/src/server/com/base/basic.rs b/opc_da/src/server/com/base/basic.rs deleted file mode 100644 index 279d94b..0000000 --- a/opc_da/src/server/com/base/basic.rs +++ /dev/null @@ -1,17 +0,0 @@ -use super::variant::Variant; - -#[derive(Clone, Default)] -pub struct Quality(pub u16); - -#[derive(Default)] -pub struct Value { - pub variant: Variant, - pub quality: Quality, - pub timestamp: Option, -} - -#[derive(Default)] -pub struct AccessRight { - pub readable: bool, - pub writable: bool, -} diff --git a/opc_da/src/server/com/base/mod.rs b/opc_da/src/server/com/base/mod.rs deleted file mode 100644 index 65b26b5..0000000 --- a/opc_da/src/server/com/base/mod.rs +++ /dev/null @@ -1,5 +0,0 @@ -pub mod basic; -pub mod variant; - -pub use basic::*; -pub use variant::*; diff --git a/opc_da/src/server/com/base/variant.rs b/opc_da/src/server/com/base/variant.rs deleted file mode 100644 index 63d4228..0000000 --- a/opc_da/src/server/com/base/variant.rs +++ /dev/null @@ -1,17 +0,0 @@ -#[derive(Clone, Default)] -pub enum Variant { - #[default] - Empty, - Bool(bool), - String(String), - I8(i8), - I16(i16), - I32(i32), - I64(i64), - F32(f32), - F64(f64), - U8(u8), - U16(u16), - U32(u32), - U64(u64), -} diff --git a/opc_da/src/server/com/builder.rs b/opc_da/src/server/com/builder.rs deleted file mode 100644 index 2fe0923..0000000 --- a/opc_da/src/server/com/builder.rs +++ /dev/null @@ -1,5 +0,0 @@ -pub struct Builder {} - -impl Builder { - pub fn register() {} -} diff --git a/opc_da/src/server/com/connection_point.rs b/opc_da/src/server/com/connection_point.rs deleted file mode 100644 index 2a2b448..0000000 --- a/opc_da/src/server/com/connection_point.rs +++ /dev/null @@ -1,73 +0,0 @@ -use std::{collections::BTreeMap, mem::ManuallyDrop}; - -use windows::Win32::System::Com::{ - IConnectionPoint, IConnectionPointContainer, IConnectionPoint_Impl, IEnumConnections, -}; - -use super::enumeration::ConnectionsEnumerator; - -#[windows::core::implement(IConnectionPoint)] -pub struct ConnectionPoint { - container: IConnectionPointContainer, - interface_id: windows::core::GUID, - next_cookie: core::sync::atomic::AtomicU32, - connections: tokio::sync::RwLock>, -} - -impl ConnectionPoint { - pub fn new( - container: IConnectionPointContainer, - interface_id: windows::core::GUID, - ) -> ConnectionPoint { - ConnectionPoint { - container, - interface_id, - next_cookie: core::sync::atomic::AtomicU32::new(0), - connections: tokio::sync::RwLock::new(BTreeMap::new()), - } - } -} - -impl IConnectionPoint_Impl for ConnectionPoint_Impl { - fn GetConnectionInterface(&self) -> windows::core::Result { - Ok(self.interface_id) - } - - fn GetConnectionPointContainer(&self) -> windows::core::Result { - Ok(self.container.clone()) - } - - fn Advise( - &self, - sink: windows::core::Ref<'_, windows::core::IUnknown>, - ) -> windows::core::Result { - let cookie = self - .next_cookie - .fetch_add(1, core::sync::atomic::Ordering::SeqCst); - self.connections - .blocking_write() - .insert(cookie, sink.unwrap().clone()); - Ok(cookie) - } - - fn Unadvise(&self, cookie: u32) -> windows::core::Result<()> { - self.connections.blocking_write().remove(&cookie); - Ok(()) - } - - fn EnumConnections(&self) -> windows::core::Result { - Ok( - windows::core::ComObjectInner::into_object(ConnectionsEnumerator::new( - self.connections - .blocking_read() - .iter() - .map(|(k, v)| windows::Win32::System::Com::CONNECTDATA { - pUnk: ManuallyDrop::new(Some(v.clone())), - dwCookie: *k, - }) - .collect(), - )) - .into_interface(), - ) - } -} diff --git a/opc_da/src/server/com/enumeration.rs b/opc_da/src/server/com/enumeration.rs deleted file mode 100644 index 9827bb4..0000000 --- a/opc_da/src/server/com/enumeration.rs +++ /dev/null @@ -1,341 +0,0 @@ -use windows::{ - Win32::{ - Foundation::{S_FALSE, S_OK}, - System::Com::{ - CONNECTDATA, IConnectionPoint, IEnumConnectionPoints, IEnumConnectionPoints_Impl, - IEnumConnections, IEnumConnections_Impl, IEnumString, IEnumString_Impl, IEnumUnknown, - IEnumUnknown_Impl, - }, - }, - core::PWSTR, -}; - -use crate::safe_call; - -use super::memory::{FreeRaw as _, IntoArrayRef, IntoComArrayRef, IntoRef as _}; - -struct Enumerator { - items: Vec, - index: core::sync::atomic::AtomicUsize, -} - -impl Enumerator { - fn new(items: Vec) -> Self { - Self { - items, - index: core::sync::atomic::AtomicUsize::default(), - } - } - - pub fn next( - &self, - count: u32, - fetched: &mut u32, - elements: &mut [T], - ) -> windows::core::HRESULT { - let current_index = self - .index - .fetch_add(count as _, core::sync::atomic::Ordering::SeqCst); - if current_index >= self.items.len() { - return S_FALSE; - } - - let end_index = (current_index + count as usize).min(self.items.len()); - let slice = &self.items[current_index..end_index]; - *fetched = slice.len() as u32; - - for (i, element) in slice.iter().enumerate() { - elements[i] = element.clone(); - } - - S_OK - } - - pub fn skip(&self, count: u32) -> windows::core::HRESULT { - let current_index = self.index.load(core::sync::atomic::Ordering::SeqCst); - let new_index = current_index.saturating_add(count as usize); - let max_index = self.items.len(); - - if new_index >= max_index { - self.index - .store(max_index, core::sync::atomic::Ordering::SeqCst); - } else { - self.index - .store(new_index, core::sync::atomic::Ordering::SeqCst); - } - - S_OK - } - - fn reset(&self) -> windows::core::HRESULT { - self.index.store(0, core::sync::atomic::Ordering::SeqCst); - S_OK - } -} - -impl Clone for Enumerator { - fn clone(&self) -> Self { - Self { - items: self.items.clone(), - index: core::sync::atomic::AtomicUsize::new( - self.index.load(core::sync::atomic::Ordering::SeqCst), - ), - } - } -} - -#[windows::core::implement(IEnumString)] -#[repr(transparent)] -pub struct StringEnumerator(Enumerator>); - -#[windows::core::implement(IEnumUnknown)] -#[repr(transparent)] -pub struct UnknownEnumerator(Enumerator); - -#[windows::core::implement(IEnumConnectionPoints)] -#[repr(transparent)] -pub struct ConnectionPointsEnumerator(Enumerator); - -#[windows::core::implement(IEnumConnections)] -#[repr(transparent)] -pub struct ConnectionsEnumerator(Enumerator); - -#[windows::core::implement(opc_da_bindings::IEnumOPCItemAttributes)] -#[repr(transparent)] -pub struct ItemAttributesEnumerator(Enumerator); - -impl StringEnumerator { - pub fn new(strings: Vec) -> Self { - Self(Enumerator::new( - strings - .into_iter() - .map(|s| s.encode_utf16().chain(Some(0)).collect()) - .collect(), - )) - } -} - -impl UnknownEnumerator { - pub fn new(items: Vec) -> Self { - Self(Enumerator::new(items)) - } -} - -impl ConnectionPointsEnumerator { - pub fn new(connection_points: Vec) -> Self { - Self(Enumerator::new(connection_points)) - } -} - -impl ConnectionsEnumerator { - pub fn new(connections: Vec) -> Self { - Self(Enumerator::new(connections)) - } -} - -impl ItemAttributesEnumerator { - pub fn new(items: Vec) -> Self { - Self(Enumerator::new(items)) - } -} - -impl IEnumString_Impl for StringEnumerator_Impl { - fn Next( - &self, - count: u32, - range_elements: *mut windows::core::PWSTR, - count_fetched: *mut u32, - ) -> windows::core::HRESULT { - let fetched = match count_fetched.into_ref() { - Ok(fetched) => fetched, - Err(e) => return e.code(), - }; - - let elements = match range_elements.into_array_ref(count) { - Ok(elements) => elements, - Err(e) => return e.code(), - }; - - let mut strings = Vec::with_capacity(count as usize); - - let code = self.0.next(count, fetched, &mut strings); - if code != S_OK { - return code; - } - - for (i, string) in strings.iter_mut().enumerate() { - let pwstr = PWSTR(string.as_mut_ptr()); - elements[i] = pwstr; - } - - S_OK - } - - fn Skip(&self, count: u32) -> windows::core::HRESULT { - self.0.skip(count) - } - - fn Reset(&self) -> windows::core::Result<()> { - self.0.reset().ok() - } - - fn Clone(&self) -> windows::core::Result { - Ok(IEnumString::from(StringEnumerator(self.0.clone()))) - } -} - -impl IEnumUnknown_Impl for UnknownEnumerator_Impl { - fn Next( - &self, - count: u32, - range_elements: *mut Option, - fetched_count: *mut u32, - ) -> windows::core::HRESULT { - let fetched = match fetched_count.into_ref() { - Ok(fetched) => fetched, - Err(e) => return e.code(), - }; - - let elements = match range_elements.into_array_ref(count) { - Ok(elements) => elements, - Err(e) => return e.code(), - }; - - let mut items = Vec::with_capacity(count as usize); - - let code = self.0.next(count, fetched, &mut items); - if code != S_OK { - return code; - } - - for (i, unk) in items.into_iter().enumerate() { - elements[i] = Some(unk); - } - - S_OK - } - - fn Skip(&self, count: u32) -> windows::core::Result<()> { - self.0.skip(count).ok() - } - - fn Reset(&self) -> windows::core::Result<()> { - self.0.reset().ok() - } - - fn Clone(&self) -> windows::core::Result { - Ok(IEnumUnknown::from(UnknownEnumerator(self.0.clone()))) - } -} - -impl IEnumConnectionPoints_Impl for ConnectionPointsEnumerator_Impl { - fn Next( - &self, - count: u32, - range_connection_points: *mut Option, - count_fetched: *mut u32, - ) -> windows::core::HRESULT { - let fetched = match count_fetched.into_ref() { - Ok(fetched) => fetched, - Err(e) => return e.code(), - }; - - let elements = match range_connection_points.into_array_ref(count) { - Ok(elements) => elements, - Err(e) => return e.code(), - }; - - let mut items = Vec::with_capacity(count as usize); - - let code = self.0.next(count, fetched, &mut items); - if code != S_OK { - return code; - } - - for (i, cp) in items.into_iter().enumerate() { - elements[i] = Some(cp); - } - - S_OK - } - - fn Skip(&self, count: u32) -> windows::core::Result<()> { - self.0.skip(count).ok() - } - - fn Reset(&self) -> windows::core::Result<()> { - self.0.reset().ok() - } - - fn Clone(&self) -> windows::core::Result { - Ok(IEnumConnectionPoints::from(ConnectionPointsEnumerator( - self.0.clone(), - ))) - } -} - -impl IEnumConnections_Impl for ConnectionsEnumerator_Impl { - fn Next( - &self, - count: u32, - range_connect_data: *mut CONNECTDATA, - count_fetched: *mut u32, - ) -> windows::core::HRESULT { - let fetched = match count_fetched.into_ref() { - Ok(fetched) => fetched, - Err(e) => return e.code(), - }; - - let elements = match range_connect_data.into_array_ref(count) { - Ok(elements) => elements, - Err(e) => return e.code(), - }; - - self.0.next(count, fetched, elements) - } - - fn Skip(&self, count: u32) -> windows::core::Result<()> { - self.0.skip(count).ok() - } - - fn Reset(&self) -> windows::core::Result<()> { - self.0.reset().ok() - } - - fn Clone(&self) -> windows::core::Result { - Ok(IEnumConnections::from(ConnectionsEnumerator( - self.0.clone(), - ))) - } -} - -impl opc_da_bindings::IEnumOPCItemAttributes_Impl for ItemAttributesEnumerator_Impl { - fn Next( - &self, - count: u32, - items: *mut *mut opc_da_bindings::tagOPCITEMATTRIBUTES, - fetched_count: *mut u32, - ) -> windows::core::Result<()> { - let fetched = fetched_count.into_ref()?; - let elements = items.into_com_array_ref(count)?; - - safe_call! { - self.0.next(count, fetched, elements).ok(), - items - } - } - - fn Skip(&self, count: u32) -> windows::core::Result<()> { - self.0.skip(count).ok() - } - - fn Reset(&self) -> windows::core::Result<()> { - self.0.reset().ok() - } - - fn Clone(&self) -> windows::core::Result { - Ok(opc_da_bindings::IEnumOPCItemAttributes::from( - ItemAttributesEnumerator(self.0.clone()), - )) - } -} diff --git a/opc_da/src/server/com/group.rs b/opc_da/src/server/com/group.rs deleted file mode 100644 index 3034716..0000000 --- a/opc_da/src/server/com/group.rs +++ /dev/null @@ -1,765 +0,0 @@ -use crate::{ - safe_call, - server::{ - com::memory::{FreeRaw as _, IntoRef as _}, - traits::GroupTrait, - }, -}; - -use super::memory::IntoComArrayRef; - -#[windows::core::implement( - // implicit implement IUnknown - opc_da_bindings::IOPCItemMgt, - opc_da_bindings::IOPCGroupStateMgt, - opc_da_bindings::IOPCGroupStateMgt2, - opc_da_bindings::IOPCPublicGroupStateMgt, - opc_da_bindings::IOPCSyncIO, - opc_da_bindings::IOPCSyncIO2, - opc_da_bindings::IOPCAsyncIO2, - opc_da_bindings::IOPCAsyncIO3, - opc_da_bindings::IOPCItemDeadbandMgt, - opc_da_bindings::IOPCItemSamplingMgt, - windows::Win32::System::Com::IConnectionPointContainer, - opc_da_bindings::IOPCAsyncIO, - windows::Win32::System::Com::IDataObject -)] -pub struct Group(pub T) -where - T: GroupTrait + 'static; - -impl core::ops::Deref for Group { - type Target = T; - - fn deref(&self) -> &Self::Target { - &self.0 - } -} - -// 1.0 required -// 2.0 required -// 3.0 required -impl opc_da_bindings::IOPCItemMgt_Impl for Group_Impl { - fn AddItems( - &self, - count: u32, - items: *const opc_da_bindings::tagOPCITEMDEF, - results: *mut *mut opc_da_bindings::tagOPCITEMRESULT, - errors: *mut *mut windows::core::HRESULT, - ) -> windows::core::Result<()> { - safe_call! { - self.add_items( - items.into_com_array_ref(count)?, - results.into_com_array_ref(count)?, - errors.into_com_array_ref(count)?, - ), - results, - errors - } - } - - fn ValidateItems( - &self, - count: u32, - items: *const opc_da_bindings::tagOPCITEMDEF, - blob_update: windows_core::BOOL, - validation_results: *mut *mut opc_da_bindings::tagOPCITEMRESULT, - errors: *mut *mut windows::core::HRESULT, - ) -> windows::core::Result<()> { - safe_call! { - self.validate_items( - items.into_com_array_ref(count)?, - blob_update, - validation_results.into_com_array_ref(count)?, - errors.into_com_array_ref(count)?, - ), - validation_results, - errors - } - } - - fn RemoveItems( - &self, - count: u32, - item_server_handles: *const u32, - errors: *mut *mut windows::core::HRESULT, - ) -> windows::core::Result<()> { - safe_call! { - self.remove_items( - item_server_handles.into_com_array_ref(count)?, - errors.into_com_array_ref(count)?, - ), - errors - } - } - - fn SetActiveState( - &self, - count: u32, - item_server_handles: *const u32, - active: windows_core::BOOL, - errors: *mut *mut windows::core::HRESULT, - ) -> windows::core::Result<()> { - safe_call! { - self.set_active_state( - item_server_handles.into_com_array_ref(count)?, - active, - errors.into_com_array_ref(count)?, - ), - errors - } - } - - fn SetClientHandles( - &self, - count: u32, - item_server_handles: *const u32, - handle_client: *const u32, - errors: *mut *mut windows::core::HRESULT, - ) -> windows::core::Result<()> { - safe_call! { - self.set_client_handles( - item_server_handles.into_com_array_ref(count)?, - handle_client.into_com_array_ref(count)?, - errors.into_com_array_ref(count)?, - ), - errors - } - } - - fn SetDatatypes( - &self, - count: u32, - item_server_handles: *const u32, - requested_data_types: *const u16, - errors: *mut *mut windows::core::HRESULT, - ) -> windows::core::Result<()> { - safe_call! { - self.set_data_types( - item_server_handles.into_com_array_ref(count)?, - requested_data_types.into_com_array_ref(count)?, - errors.into_com_array_ref(count)?, - ), - errors - } - } - - fn CreateEnumerator( - &self, - reference_interface_id: *const windows::core::GUID, - ) -> windows::core::Result { - safe_call! { - self.create_enumerator(reference_interface_id.into_ref()?), - } - } -} - -// 1.0 required -// 2.0 required -// 3.0 required -impl opc_da_bindings::IOPCGroupStateMgt_Impl for Group_Impl { - fn GetState( - &self, - update_rate: *mut u32, - active: *mut windows_core::BOOL, - name: *mut windows::core::PWSTR, - time_bias: *mut i32, - percent_deadband: *mut f32, - locale_id: *mut u32, - group_client_handle: *mut u32, - item_server_handle_group: *mut u32, - ) -> windows::core::Result<()> { - self.get_state( - update_rate.into_ref()?, - active.into_ref()?, - name.into_ref()?, - time_bias.into_ref()?, - percent_deadband.into_ref()?, - locale_id.into_ref()?, - group_client_handle.into_ref()?, - item_server_handle_group.into_ref()?, - ) - } - - fn SetState( - &self, - requested_update_rate: *const u32, - revised_update_rate: *mut u32, - active: *const windows_core::BOOL, - time_bias: *const i32, - percent_deadband: *const f32, - locale_id: *const u32, - group_client_handle: *const u32, - ) -> windows::core::Result<()> { - self.set_state( - requested_update_rate.into_ref()?, - revised_update_rate.into_ref()?, - active.into_ref()?, - time_bias.into_ref()?, - percent_deadband.into_ref()?, - locale_id.into_ref()?, - group_client_handle.into_ref()?, - ) - } - - fn SetName(&self, name: &windows::core::PCWSTR) -> windows::core::Result<()> { - self.set_name(name) - } - - fn CloneGroup( - &self, - name: &windows::core::PCWSTR, - reference_interface_id: *const windows::core::GUID, - ) -> windows::core::Result { - self.clone_group(name, reference_interface_id.into_ref()?) - } -} - -// 1.0 N/A -// 2.0 N/A -// 3.0 required -impl opc_da_bindings::IOPCGroupStateMgt2_Impl for Group_Impl { - fn SetKeepAlive(&self, keep_alive_time: u32) -> windows::core::Result { - self.set_keep_alive(keep_alive_time) - } - - fn GetKeepAlive(&self) -> windows::core::Result { - self.get_keep_alive() - } -} - -// 1.0 optional -// 2.0 optional -// 3.0 N/A -impl opc_da_bindings::IOPCPublicGroupStateMgt_Impl for Group_Impl { - fn GetState(&self) -> windows::core::Result { - self.get_public_group_state() - } - - fn MoveToPublic(&self) -> windows::core::Result<()> { - self.move_to_public() - } -} - -// 1.0 required -// 2.0 required -// 3.0 required -impl opc_da_bindings::IOPCSyncIO_Impl for Group_Impl { - fn Read( - &self, - source: opc_da_bindings::tagOPCDATASOURCE, - count: u32, - item_server_handles: *const u32, - item_values: *mut *mut opc_da_bindings::tagOPCITEMSTATE, - errors: *mut *mut windows::core::HRESULT, - ) -> windows::core::Result<()> { - safe_call! { - self.read( - source, - item_server_handles.into_com_array_ref(count)?, - item_values.into_com_array_ref(count)?, - errors.into_com_array_ref(count)?, - ), - item_values, - errors - } - } - - fn Write( - &self, - count: u32, - item_server_handles: *const u32, - item_values: *const windows::Win32::System::Variant::VARIANT, - errors: *mut *mut windows::core::HRESULT, - ) -> windows::core::Result<()> { - safe_call! { - self.write( - item_server_handles.into_com_array_ref(count)?, - item_values.into_com_array_ref(count)?, - errors.into_com_array_ref(count)?, - ), - errors - } - } -} - -// 1.0 N/A -// 2.0 N/A -// 3.0 required -impl opc_da_bindings::IOPCSyncIO2_Impl for Group_Impl { - fn ReadMaxAge( - &self, - count: u32, - item_server_handles: *const u32, - max_age: *const u32, - values: *mut *mut windows::Win32::System::Variant::VARIANT, - qualities: *mut *mut u16, - timestamps: *mut *mut windows::Win32::Foundation::FILETIME, - errors: *mut *mut windows::core::HRESULT, - ) -> windows::core::Result<()> { - safe_call! { - self.read_max_age( - item_server_handles.into_com_array_ref(count)?, - max_age.into_com_array_ref(count)?, - values.into_com_array_ref(count)?, - qualities.into_com_array_ref(count)?, - timestamps.into_com_array_ref(count)?, - errors.into_com_array_ref(count)?, - ), - values, - qualities, - timestamps, - errors - } - } - - fn WriteVQT( - &self, - count: u32, - item_server_handles: *const u32, - item_vqt: *const opc_da_bindings::tagOPCITEMVQT, - errors: *mut *mut windows::core::HRESULT, - ) -> windows::core::Result<()> { - safe_call! { - self.write_vqt( - count, - item_server_handles.into_com_array_ref(count)?, - item_vqt.into_com_array_ref(count)?, - errors.into_com_array_ref(count)?, - ), - errors - } - } -} - -// 1.0 N/A -// 2.0 required -// 3.0 required -impl opc_da_bindings::IOPCAsyncIO2_Impl for Group_Impl { - fn Read( - &self, - count: u32, - item_server_handles: *const u32, - transaction_id: u32, - cancel_id: *mut u32, - errors: *mut *mut windows::core::HRESULT, - ) -> windows::core::Result<()> { - safe_call! { - self.read2( - item_server_handles.into_com_array_ref(count)?, - transaction_id, - cancel_id.into_ref()?, - errors.into_com_array_ref(count)?, - ), - errors - } - } - - fn Write( - &self, - count: u32, - item_server_handles: *const u32, - item_values: *const windows::Win32::System::Variant::VARIANT, - transaction_id: u32, - cancel_id: *mut u32, - errors: *mut *mut windows::core::HRESULT, - ) -> windows::core::Result<()> { - safe_call! { - self.write2( - count, - item_server_handles.into_com_array_ref(count)?, - item_values.into_com_array_ref(count)?, - transaction_id, - cancel_id.into_ref()?, - errors.into_com_array_ref(count)?, - ), - errors - } - } - - fn Refresh2( - &self, - source: opc_da_bindings::tagOPCDATASOURCE, - transaction_id: u32, - ) -> windows::core::Result { - self.refresh2(source, transaction_id) - } - - fn Cancel2(&self, cancel_id: u32) -> windows::core::Result<()> { - self.cancel2(cancel_id) - } - - fn SetEnable(&self, enable: windows_core::BOOL) -> windows::core::Result<()> { - self.set_enable(enable) - } - - fn GetEnable(&self) -> windows::core::Result { - self.get_enable() - } -} - -// 1.0 N/A -// 2.0 N/A -// 3.0 required -impl opc_da_bindings::IOPCAsyncIO3_Impl for Group_Impl { - fn ReadMaxAge( - &self, - count: u32, - item_server_handles: *const u32, - max_age: *const u32, - transaction_id: u32, - cancel_id: *mut u32, - errors: *mut *mut windows::core::HRESULT, - ) -> windows::core::Result<()> { - safe_call! { - self.read_max_age2( - item_server_handles.into_com_array_ref(count)?, - max_age.into_com_array_ref(count)?, - transaction_id, - cancel_id.into_ref()?, - errors.into_com_array_ref(count)?, - ), - errors - } - } - - fn WriteVQT( - &self, - count: u32, - item_server_handles: *const u32, - item_vqt: *const opc_da_bindings::tagOPCITEMVQT, - transaction_id: u32, - cancel_id: *mut u32, - errors: *mut *mut windows::core::HRESULT, - ) -> windows::core::Result<()> { - safe_call! { - self.write_vqt2( - item_server_handles.into_com_array_ref(count)?, - item_vqt.into_com_array_ref(count)?, - transaction_id, - cancel_id.into_ref()?, - errors.into_com_array_ref(count)?, - ), - errors - } - } - - fn RefreshMaxAge(&self, max_age: u32, transaction_id: u32) -> windows::core::Result { - self.refresh_max_age(max_age, transaction_id) - } -} - -// 1.0 N/A -// 2.0 N/A -// 3.0 required -impl opc_da_bindings::IOPCItemDeadbandMgt_Impl for Group_Impl { - fn SetItemDeadband( - &self, - count: u32, - item_server_handles: *const u32, - percent_deadband: *const f32, - errors: *mut *mut windows::core::HRESULT, - ) -> windows::core::Result<()> { - safe_call! { - self.set_item_deadband( - item_server_handles.into_com_array_ref(count)?, - percent_deadband.into_com_array_ref(count)?, - errors.into_com_array_ref(count)?, - ), - errors - } - } - - fn GetItemDeadband( - &self, - count: u32, - item_server_handles: *const u32, - percent_deadband: *mut *mut f32, - errors: *mut *mut windows::core::HRESULT, - ) -> windows::core::Result<()> { - safe_call! { - self.get_item_deadband( - item_server_handles.into_com_array_ref(count)?, - percent_deadband.into_com_array_ref(count)?, - errors.into_com_array_ref(count)?, - ), - percent_deadband, - errors - } - } - - fn ClearItemDeadband( - &self, - count: u32, - item_server_handles: *const u32, - errors: *mut *mut windows::core::HRESULT, - ) -> windows::core::Result<()> { - safe_call! { - self.clear_item_deadband( - item_server_handles.into_com_array_ref(count)?, - errors.into_com_array_ref(count)?, - ), - errors - } - } -} - -// 1.0 N/A -// 2.0 N/A -// 3.0 optional -impl opc_da_bindings::IOPCItemSamplingMgt_Impl for Group_Impl { - fn SetItemSamplingRate( - &self, - count: u32, - item_server_handles: *const u32, - requested_sampling_rate: *const u32, - revised_sampling_rate: *mut *mut u32, - errors: *mut *mut windows::core::HRESULT, - ) -> windows::core::Result<()> { - safe_call! { - self.set_item_sampling_rate( - count, - item_server_handles.into_com_array_ref(count)?, - requested_sampling_rate.into_com_array_ref(count)?, - revised_sampling_rate.into_com_array_ref(count)?, - errors.into_com_array_ref(count)?, - ), - revised_sampling_rate, - errors - } - } - - fn GetItemSamplingRate( - &self, - count: u32, - item_server_handles: *const u32, - sampling_rate: *mut *mut u32, - errors: *mut *mut windows::core::HRESULT, - ) -> windows::core::Result<()> { - safe_call! { - self.get_item_sampling_rate( - item_server_handles.into_com_array_ref(count)?, - sampling_rate.into_com_array_ref(count)?, - errors.into_com_array_ref(count)?, - ), - sampling_rate, - errors - } - } - - fn ClearItemSamplingRate( - &self, - count: u32, - item_server_handles: *const u32, - errors: *mut *mut windows::core::HRESULT, - ) -> windows::core::Result<()> { - safe_call! { - self.clear_item_sampling_rate( - item_server_handles.into_com_array_ref(count)?, - errors.into_com_array_ref(count)?, - ), - errors - } - } - - fn SetItemBufferEnable( - &self, - count: u32, - item_server_handles: *const u32, - penable: *const windows_core::BOOL, - errors: *mut *mut windows::core::HRESULT, - ) -> windows::core::Result<()> { - safe_call! { - self.set_item_buffer_enable( - item_server_handles.into_com_array_ref(count)?, - penable.into_ref()?, - errors.into_com_array_ref(count)?, - ), - errors - } - } - - fn GetItemBufferEnable( - &self, - count: u32, - item_server_handles: *const u32, - enable: *mut *mut windows_core::BOOL, - errors: *mut *mut windows::core::HRESULT, - ) -> windows::core::Result<()> { - safe_call! { - self.get_item_buffer_enable( - item_server_handles.into_com_array_ref(count)?, - enable.into_com_array_ref(count)?, - errors.into_com_array_ref(count)?, - ), - enable, - errors - } - } -} - -// 1.0 N/A -// 2.0 required -// 3.0 required -impl windows::Win32::System::Com::IConnectionPointContainer_Impl - for Group_Impl -{ - fn EnumConnectionPoints( - &self, - ) -> windows::core::Result { - self.enum_connection_points() - } - - fn FindConnectionPoint( - &self, - reference_interface_id: *const windows::core::GUID, - ) -> windows::core::Result { - self.find_connection_point(reference_interface_id.into_ref()?) - } -} - -// 1.0 required -// 2.0 optional -// 3.0 N/A -impl opc_da_bindings::IOPCAsyncIO_Impl for Group_Impl { - fn Read( - &self, - connection: u32, - source: opc_da_bindings::tagOPCDATASOURCE, - count: u32, - item_server_handles: *const u32, - transaction_id: *mut u32, - errors: *mut *mut windows::core::HRESULT, - ) -> windows::core::Result<()> { - safe_call! { - self.read3( - connection, - source, - item_server_handles.into_com_array_ref(count)?, - transaction_id.into_ref()?, - errors.into_com_array_ref(count)?, - ), - errors - } - } - - fn Write( - &self, - connection: u32, - count: u32, - item_server_handles: *const u32, - item_values: *const windows::Win32::System::Variant::VARIANT, - transaction_id: *mut u32, - errors: *mut *mut windows::core::HRESULT, - ) -> windows::core::Result<()> { - safe_call! { - self.write3( - connection, - item_server_handles.into_com_array_ref(count)?, - item_values.into_com_array_ref(count)?, - transaction_id.into_ref()?, - errors.into_com_array_ref(count)?, - ), - errors - } - } - - fn Refresh( - &self, - connection: u32, - source: opc_da_bindings::tagOPCDATASOURCE, - ) -> windows::core::Result { - self.refresh(connection, source) - } - - fn Cancel(&self, transaction_id: u32) -> windows::core::Result<()> { - self.cancel(transaction_id) - } -} - -// 1.0 required -// 2.0 optional -// 3.0 N/A -impl windows::Win32::System::Com::IDataObject_Impl for Group_Impl { - fn GetData( - &self, - format_etc_in: *const windows::Win32::System::Com::FORMATETC, - ) -> windows::core::Result { - self.get_data(format_etc_in.into_ref()?) - } - - fn GetDataHere( - &self, - format_etc_in: *const windows::Win32::System::Com::FORMATETC, - storage_medium: *mut windows::Win32::System::Com::STGMEDIUM, - ) -> windows::core::Result<()> { - self.get_data_here(format_etc_in.into_ref()?, storage_medium.into_ref()?) - } - - fn QueryGetData( - &self, - format_etc_in: *const windows::Win32::System::Com::FORMATETC, - ) -> windows::core::HRESULT { - let format_etc_in = match format_etc_in.into_ref() { - Ok(format_etc_in) => format_etc_in, - Err(err) => return err.code(), - }; - - self.query_get_data(format_etc_in) - } - - fn GetCanonicalFormatEtc( - &self, - format_etc_in: *const windows::Win32::System::Com::FORMATETC, - format_etc_inout: *mut windows::Win32::System::Com::FORMATETC, - ) -> windows::core::HRESULT { - let format_etc_in = match format_etc_in.into_ref() { - Ok(format_etc_in) => format_etc_in, - Err(err) => return err.code(), - }; - - let format_etc_inout = match format_etc_inout.into_ref() { - Ok(format_etc_inout) => format_etc_inout, - Err(err) => return err.code(), - }; - - self.get_canonical_format_etc(format_etc_in, format_etc_inout) - } - - fn SetData( - &self, - format_etc_in: *const windows::Win32::System::Com::FORMATETC, - storage_medium: *const windows::Win32::System::Com::STGMEDIUM, - release: windows_core::BOOL, - ) -> windows::core::Result<()> { - self.set_data( - format_etc_in.into_ref()?, - storage_medium.into_ref()?, - release, - ) - } - - fn EnumFormatEtc( - &self, - direction: u32, - ) -> windows::core::Result { - self.enum_format_etc(direction) - } - - fn DAdvise( - &self, - format_etc_in: *const windows::Win32::System::Com::FORMATETC, - adv: u32, - sink: windows::core::Ref<'_, windows::Win32::System::Com::IAdviseSink>, - ) -> windows::core::Result { - self.data_advise(format_etc_in.into_ref()?, adv, sink) - } - - fn DUnadvise(&self, connection: u32) -> windows::core::Result<()> { - self.data_unadvise(connection) - } - - fn EnumDAdvise(&self) -> windows::core::Result { - self.enum_data_advise() - } -} diff --git a/opc_da/src/server/com/item.rs b/opc_da/src/server/com/item.rs deleted file mode 100644 index 8b13789..0000000 --- a/opc_da/src/server/com/item.rs +++ /dev/null @@ -1 +0,0 @@ - diff --git a/opc_da/src/server/com/memory.rs b/opc_da/src/server/com/memory.rs deleted file mode 100644 index ffedb57..0000000 --- a/opc_da/src/server/com/memory.rs +++ /dev/null @@ -1,220 +0,0 @@ -use windows::Win32::{Foundation::E_POINTER, System::Com::CoTaskMemAlloc}; - -pub trait IntoRef { - fn into_ref(self) -> windows::core::Result; -} - -pub trait IntoArrayRef { - fn into_array_ref(self, count: u32) -> windows::core::Result; -} - -pub trait IntoComArrayRef { - fn into_com_array_ref(self, count: u32) -> windows::core::Result; -} - -pub trait FreeRaw { - fn free_raw(self); -} - -#[macro_export] -macro_rules! safe_call { - ($call:expr, $($p:ident),*) => { - let result = $call; - - if result.is_err() { - $($p.free_raw();)* - } - - result - }; -} - -impl<'a, P> IntoRef<&'a P> for *const P { - #[inline(always)] - fn into_ref(self) -> windows::core::Result<&'a P> { - if self.is_null() { - Err(windows::core::Error::from_hresult(E_POINTER)) - } else { - Ok(unsafe { &*self }) - } - } -} - -impl<'a, P> IntoRef<&'a mut P> for *mut P { - #[inline(always)] - fn into_ref(self) -> windows::core::Result<&'a mut P> { - if self.is_null() { - Err(windows::core::Error::from_hresult(E_POINTER)) - } else { - Ok(unsafe { &mut *self }) - } - } -} - -impl<'a, P> IntoArrayRef<&'a mut [P]> for *mut P { - #[inline(always)] - fn into_array_ref(self, count: u32) -> windows::core::Result<&'a mut [P]> { - if self.is_null() { - Err(windows::core::Error::from_hresult(E_POINTER)) - } else { - unsafe { Ok(std::slice::from_raw_parts_mut(self, count as usize)) } - } - } -} - -impl<'a, P: windows::core::Interface> IntoArrayRef<&'a mut [Option

]> - for windows::core::OutRef<'a, P> -{ - #[inline(always)] - fn into_array_ref(self, count: u32) -> windows::core::Result<&'a mut [Option

]> { - if self.is_null() { - Err(windows::core::Error::from_hresult(E_POINTER)) - } else { - unsafe { - Ok(std::slice::from_raw_parts_mut( - *(&self as *const _ as *mut *mut Option

), - count as usize, - )) - } - } - } -} - -impl

FreeRaw for *mut *mut P { - #[inline(always)] - fn free_raw(self) { - unsafe { - windows::Win32::System::Com::CoTaskMemFree(if self.is_null() { - None - } else { - Some(*self as _) - }); - } - } -} - -impl<'a, P> IntoComArrayRef<&'a [P]> for *const P { - #[inline(always)] - fn into_com_array_ref(self, count: u32) -> windows::core::Result<&'a [P]> { - if self.is_null() { - Err(windows::core::Error::from_hresult(E_POINTER)) - } else { - Ok(unsafe { core::slice::from_raw_parts(self, count as usize) }) - } - } -} - -impl<'a, P> IntoComArrayRef<&'a mut [P]> for *mut *mut P { - #[inline(always)] - fn into_com_array_ref(self, count: u32) -> windows::core::Result<&'a mut [P]> { - if self.is_null() { - Err(windows::core::Error::from_hresult(E_POINTER)) - } else { - unsafe { - let new_pointer = - CoTaskMemAlloc(std::mem::size_of::

() * count as usize) as *mut P; - - if new_pointer.is_null() { - return Err(windows::core::Error::from_hresult(E_POINTER)); - } else { - *self = new_pointer; - } - - Ok(std::slice::from_raw_parts_mut(new_pointer, count as usize)) - } - } - } -} - -impl<'a, P1, P2> IntoComArrayRef> for (*const P1, *const P2) { - #[inline(always)] - fn into_com_array_ref(self, count: u32) -> windows::core::Result> { - let (p0, p1) = self; - - Ok(p0 - .into_com_array_ref(count)? - .iter() - .zip(p1.into_com_array_ref(count)?.iter()) - .collect()) - } -} - -impl<'a, P1, P2> IntoComArrayRef> for (*const P1, *mut *mut P2) { - #[inline(always)] - fn into_com_array_ref(self, count: u32) -> windows::core::Result> { - let (p0, p1) = self; - - Ok(p0 - .into_com_array_ref(count)? - .iter() - .zip(p1.into_com_array_ref(count)?.iter_mut()) - .collect()) - } -} - -impl<'a, P1, P2> IntoComArrayRef> for (*mut *mut P1, *mut *mut P2) { - #[inline(always)] - fn into_com_array_ref( - self, - count: u32, - ) -> windows::core::Result> { - let (p0, p1) = self; - - Ok(p0 - .into_com_array_ref(count)? - .iter_mut() - .zip(p1.into_com_array_ref(count)?.iter_mut()) - .collect()) - } -} - -impl<'a, C1, M1, M2> IntoComArrayRef> - for (*const C1, (*mut *mut M1, *mut *mut M2)) -{ - #[inline(always)] - fn into_com_array_ref( - self, - count: u32, - ) -> windows::core::Result> { - let (c, m) = self; - - Ok(c.into_com_array_ref(count)? - .iter() - .zip(m.into_com_array_ref(count)?) - .collect()) - } -} - -impl<'a, C1, C2, M1> IntoComArrayRef> - for ((*const C1, *const C2), *mut *mut M1) -{ - #[inline(always)] - fn into_com_array_ref( - self, - count: u32, - ) -> windows::core::Result> { - let (c, m) = self; - - Ok(c.into_com_array_ref(count)? - .into_iter() - .zip(m.into_com_array_ref(count)?) - .collect()) - } -} - -impl<'a, C1, C2, M1, M2> IntoComArrayRef> - for ((*const C1, *const C2), (*mut *mut M1, *mut *mut M2)) -{ - #[inline(always)] - fn into_com_array_ref( - self, - count: u32, - ) -> windows::core::Result> { - let (c, m) = self; - - Ok(c.into_com_array_ref(count)? - .into_iter() - .zip(m.into_com_array_ref(count)?) - .collect()) - } -} diff --git a/opc_da/src/server/com/mod.rs b/opc_da/src/server/com/mod.rs deleted file mode 100644 index 4ba0618..0000000 --- a/opc_da/src/server/com/mod.rs +++ /dev/null @@ -1,16 +0,0 @@ -pub mod base; -pub mod builder; -pub mod connection_point; -#[allow(clippy::not_unsafe_ptr_arg_deref)] -pub mod enumeration; -#[allow(clippy::not_unsafe_ptr_arg_deref)] -pub mod group; -pub mod item; -#[allow(clippy::not_unsafe_ptr_arg_deref)] -pub mod memory; -#[allow(clippy::not_unsafe_ptr_arg_deref)] -pub mod server; -#[allow(clippy::not_unsafe_ptr_arg_deref)] -pub mod utils; -#[allow(clippy::not_unsafe_ptr_arg_deref)] -pub mod variant; diff --git a/opc_da/src/server/com/server.rs b/opc_da/src/server/com/server.rs deleted file mode 100644 index 6cf251a..0000000 --- a/opc_da/src/server/com/server.rs +++ /dev/null @@ -1,558 +0,0 @@ -use crate::{ - server::traits::{ItemOptionalVqt, ItemWithMaxAge, ServerTrait}, - utils::{TryToLocal as _, TryToNative as _}, -}; - -use super::{ - enumeration::{ConnectionPointsEnumerator, StringEnumerator}, - utils::{ - PointerReader, PointerWriter, TryReadArray, TryWriteArrayPointer, TryWriteInto, - TryWritePointer, TryWriteTo, - }, -}; - -#[windows::core::implement( - // implicit implement IUnknown - opc_da_bindings::IOPCServer, - opc_comn_bindings::IOPCCommon, - windows::Win32::System::Com::IConnectionPointContainer, - opc_da_bindings::IOPCItemProperties, - opc_da_bindings::IOPCBrowse, - opc_da_bindings::IOPCServerPublicGroups, - opc_da_bindings::IOPCBrowseServerAddressSpace, - opc_da_bindings::IOPCItemIO -)] -pub struct Server(pub T) -where - T: ServerTrait + 'static; - -impl core::ops::Deref for Server { - type Target = T; - - fn deref(&self) -> &Self::Target { - &self.0 - } -} - -// 1.0 required -// 2.0 required -// 3.0 required -impl opc_da_bindings::IOPCServer_Impl for Server_Impl { - fn AddGroup( - &self, - name: &windows::core::PCWSTR, - active: windows_core::BOOL, - requested_update_rate: u32, - client_group: u32, - time_bias: *const i32, - percent_deadband: *const f32, - locale_id: u32, - server_group: *mut u32, - revised_update_rate: *mut u32, - reference_interface_id: *const windows::core::GUID, - unknown: windows::core::OutRef<'_, windows::core::IUnknown>, - ) -> windows::core::Result<()> { - let info = self.add_group( - unsafe { name.to_string() }?, - active.as_bool(), - requested_update_rate, - client_group, - unsafe { time_bias.as_ref() }.copied(), - unsafe { percent_deadband.as_ref() }.copied(), - locale_id, - unsafe { reference_interface_id.as_ref() }.map(|id| id.to_u128()), - )?; - - PointerWriter::try_write(info.server_group, server_group)?; - PointerWriter::try_write(info.revised_update_rate, revised_update_rate)?; - PointerWriter::try_write_into(info.unknown, unknown)?; - - Ok(()) - } - - fn GetErrorString( - &self, - error: windows::core::HRESULT, - locale: u32, - ) -> windows::core::Result { - let s = self.get_error_string_locale(error.0, locale)?; - PointerWriter::try_write_to(&s) - } - - fn GetGroupByName( - &self, - name: &windows::core::PCWSTR, - reference_interface_id: *const windows::core::GUID, - ) -> windows::core::Result { - self.get_group_by_name( - unsafe { name.to_string() }?, - if reference_interface_id.is_null() { - None - } else { - Some(unsafe { *reference_interface_id }.to_u128()) - }, - ) - } - - fn GetStatus(&self) -> windows::core::Result<*mut opc_da_bindings::tagOPCSERVERSTATUS> { - let status: opc_da_bindings::tagOPCSERVERSTATUS = self.get_status()?.try_into()?; - PointerWriter::try_write_to(status) - } - - fn RemoveGroup( - &self, - server_group: u32, - force: windows_core::BOOL, - ) -> windows::core::Result<()> { - self.remove_group(server_group, force.as_bool()) - } - - fn CreateGroupEnumerator( - &self, - scope: opc_da_bindings::tagOPCENUMSCOPE, - reference_interface_id: *const windows::core::GUID, - ) -> windows::core::Result { - self.create_group_enumerator( - scope.try_to_local()?, - unsafe { reference_interface_id.as_ref() }.map(|id| id.to_u128()), - ) - } -} - -// 1.0 N/A -// 2.0 required -// 3.0 required -impl opc_comn_bindings::IOPCCommon_Impl for Server_Impl { - fn SetLocaleID(&self, locale_id: u32) -> windows::core::Result<()> { - self.set_locale_id(locale_id) - } - - fn GetLocaleID(&self) -> windows::core::Result { - self.get_locale_id() - } - - fn QueryAvailableLocaleIDs( - &self, - count: *mut u32, - locale_ids: *mut *mut u32, - ) -> windows::core::Result<()> { - let available_locale_ids = self.query_available_locale_ids()?; - PointerWriter::try_write(available_locale_ids.len() as _, count)?; - PointerWriter::try_write_array_pointer(&available_locale_ids, locale_ids)?; - Ok(()) - } - - fn GetErrorString( - &self, - error: windows::core::HRESULT, - ) -> windows::core::Result { - let s = self.get_error_string(error.0).map_err(|e| { - // Map internal errors to appropriate COM errors - windows::core::Error::new(windows::Win32::Foundation::E_FAIL, e.to_string()) - })?; - let mut out = windows::core::PWSTR::null(); - PointerWriter::try_write_into(&s, &mut out).map_err(|e| { - // Handle allocation failures - windows::core::Error::new(windows::Win32::Foundation::E_OUTOFMEMORY, e.to_string()) - })?; - Ok(out) - } - - fn SetClientName(&self, name: &windows::core::PCWSTR) -> windows::core::Result<()> { - self.set_client_name(unsafe { name.to_string() }?) - } -} - -// 1.0 N/A -// 2.0 required -// 3.0 required -impl windows::Win32::System::Com::IConnectionPointContainer_Impl - for Server_Impl -{ - fn EnumConnectionPoints( - &self, - ) -> windows::core::Result { - let connection_points = self.enum_connection_points()?; - - Ok( - windows::core::ComObjectInner::into_object(ConnectionPointsEnumerator::new( - connection_points, - )) - .into_interface(), - ) - } - - fn FindConnectionPoint( - &self, - reference_interface_id: *const windows::core::GUID, - ) -> windows::core::Result { - self.find_connection_point(reference_interface_id) - } -} - -// 1.0 N/A -// 2.0 required -// 3.0 N/A -impl opc_da_bindings::IOPCItemProperties_Impl for Server_Impl { - fn QueryAvailableProperties( - &self, - item_id: &windows::core::PCWSTR, - count: *mut u32, - property_ids: *mut *mut u32, - descriptions: *mut *mut windows::core::PWSTR, - data_types: *mut *mut u16, - ) -> windows::core::Result<()> { - let vec = self.query_available_properties(unsafe { item_id.to_string() }?)?; - - PointerWriter::try_write(vec.len() as _, count)?; - - PointerWriter::try_write_array_pointer( - &vec.iter().map(|p| p.property_id).collect::>(), - property_ids, - )?; - - PointerWriter::try_write_into( - &vec.iter() - .map(|p| p.description.as_str()) - .collect::>(), - descriptions, - )?; - - PointerWriter::try_write_array_pointer( - &vec.iter().map(|p| p.data_type).collect::>(), - data_types, - )?; - - Ok(()) - } - - fn GetItemProperties( - &self, - item_id: &windows::core::PCWSTR, - count: u32, - property_ids: *const u32, - data: *mut *mut windows::Win32::System::Variant::VARIANT, - errors: *mut *mut windows::core::HRESULT, - ) -> windows::core::Result<()> { - let property_ids = PointerReader::try_read_array(count, property_ids)?; - - let vec = self.get_item_properties(unsafe { item_id.to_string() }?, property_ids)?; - - PointerWriter::try_write_array_pointer( - &vec.iter().map(|p| p.error).collect::>(), - errors, - )?; - - PointerWriter::try_write_array_pointer( - &vec.into_iter().map(|p| p.data.into()).collect::>(), - data, - )?; - - Ok(()) - } - - fn LookupItemIDs( - &self, - item_id: &windows::core::PCWSTR, - count: u32, - property_ids: *const u32, - new_item_ids: *mut *mut windows::core::PWSTR, - errors: *mut *mut windows::core::HRESULT, - ) -> windows::core::Result<()> { - let property_ids = PointerReader::try_read_array(count, property_ids)?; - - let vec = self.lookup_item_ids(unsafe { item_id.to_string() }?, property_ids)?; - - PointerWriter::try_write_into( - &vec.iter() - .map(|p| p.new_item_id.as_str()) - .collect::>(), - new_item_ids, - )?; - - PointerWriter::try_write_array_pointer( - &vec.iter().map(|p| p.error).collect::>(), - errors, - )?; - - Ok(()) - } -} - -// 1.0 N/A -// 2.0 N/A -// 3.0 required -impl opc_da_bindings::IOPCBrowse_Impl for Server_Impl { - fn GetProperties( - &self, - item_count: u32, - item_ids: *const windows::core::PCWSTR, - return_property_values: windows_core::BOOL, - property_count: u32, - property_ids: *const u32, - item_properties: *mut *mut opc_da_bindings::tagOPCITEMPROPERTIES, - ) -> windows::core::Result<()> { - let item_ids = PointerReader::try_read_array(item_count, item_ids)?; - let property_ids = PointerReader::try_read_array(property_count, property_ids)?; - - let properties = - self.get_properties(item_ids, return_property_values.as_bool(), property_ids)?; - - PointerWriter::try_write_array_pointer( - &properties - .into_iter() - .map(|item| match item.try_into() { - Ok(item) => item, - Err(error) => opc_da_bindings::tagOPCITEMPROPERTIES { - hrErrorID: (error as windows::core::Error).code(), - ..Default::default() - }, - }) - .collect::>(), - item_properties, - )?; - - Ok(()) - } - - fn Browse( - &self, - item_id: &windows::core::PCWSTR, - continuation_point: *mut windows::core::PWSTR, - max_elements_returned: u32, - browse_filter: opc_da_bindings::tagOPCBROWSEFILTER, - element_name_filter: &windows::core::PCWSTR, - vendor_filter: &windows::core::PCWSTR, - return_all_properties: windows_core::BOOL, - return_property_values: windows_core::BOOL, - property_count: u32, - property_ids: *const u32, - more_elements: *mut windows_core::BOOL, - count: *mut u32, - browse_elements: *mut *mut opc_da_bindings::tagOPCBROWSEELEMENT, - ) -> windows::core::Result<()> { - let item_id = unsafe { item_id.to_string()? }; - let element_name_filter = unsafe { element_name_filter.to_string()? }; - let vendor_filter = unsafe { vendor_filter.to_string()? }; - let property_ids = PointerReader::try_read_array(property_count, property_ids)?; - - let result = self.browse( - item_id, - unsafe { - continuation_point - .as_ref() - .map(|s| s.to_string()) - .transpose()? - }, - max_elements_returned, - browse_filter.try_into()?, - element_name_filter, - vendor_filter, - return_all_properties.as_bool(), - return_property_values.as_bool(), - property_ids, - )?; - - PointerWriter::try_write(result.elements.len() as _, count)?; - - PointerWriter::try_write_array_pointer( - &result - .elements - .into_iter() - .map(|element| match element.try_into() { - Ok(element) => element, - Err(error) => { - let mut element = opc_da_bindings::tagOPCBROWSEELEMENT::default(); - element.ItemProperties.hrErrorID = (error as windows::core::Error).code(); - element - } - }) - .collect::>(), - browse_elements, - )?; - - PointerWriter::try_write(result.more_elements.into(), more_elements)?; - - match result.continuation_point { - Some(new_continuation_point) => { - PointerWriter::try_write_into(&new_continuation_point, continuation_point)? - } - None => unsafe { - *continuation_point = windows::core::PWSTR::null(); - }, - } - - Ok(()) - } -} - -// 1.0 optional -// 2.0 optional -// 3.0 N/A -impl opc_da_bindings::IOPCServerPublicGroups_Impl for Server_Impl { - fn GetPublicGroupByName( - &self, - name: &windows::core::PCWSTR, - reference_interface_id: *const windows::core::GUID, - ) -> windows::core::Result { - if reference_interface_id.is_null() { - return Err(windows::core::Error::new( - windows::Win32::Foundation::E_INVALIDARG, - "Null reference_interface_id", - )); - } - - self.get_public_group_by_name( - unsafe { name.to_string() }?, - unsafe { *reference_interface_id }.to_u128(), - ) - } - - fn RemovePublicGroup( - &self, - server_group: u32, - force: windows_core::BOOL, - ) -> windows::core::Result<()> { - self.remove_public_group(server_group, force.as_bool()) - } -} - -// 1.0 optional -// 2.0 optional -// 3.0 N/A -impl opc_da_bindings::IOPCBrowseServerAddressSpace_Impl - for Server_Impl -{ - fn QueryOrganization(&self) -> windows::core::Result { - self.query_organization().map(Into::into) - } - - fn ChangeBrowsePosition( - &self, - browse_direction: opc_da_bindings::tagOPCBROWSEDIRECTION, - string: &windows::core::PCWSTR, - ) -> windows::core::Result<()> { - self.change_browse_position((browse_direction, unsafe { string.to_string() }?).try_into()?) - } - - fn BrowseOPCItemIDs( - &self, - browse_filter_type: opc_da_bindings::tagOPCBROWSETYPE, - filter_criteria: &windows::core::PCWSTR, - variant_data_type_filter: u16, - access_rights_filter: u32, - ) -> windows::core::Result { - self.browse_opc_item_ids( - browse_filter_type.try_into()?, - unsafe { filter_criteria.to_string() }?, - variant_data_type_filter, - access_rights_filter, - ) - } - - fn GetItemID( - &self, - item_data_id: &windows::core::PCWSTR, - ) -> windows::core::Result { - let item_id = self.get_item_id(unsafe { item_data_id.to_string() }?)?; - PointerWriter::try_write_to(&item_id) - } - - fn BrowseAccessPaths( - &self, - item_id: &windows::core::PCWSTR, - ) -> windows::core::Result { - let access_paths = self.browse_access_paths(unsafe { item_id.to_string() }?)?; - - Ok( - windows::core::ComObjectInner::into_object(StringEnumerator::new(access_paths)) - .into_interface(), - ) - } -} - -// 1.0 N/A -// 2.0 N/A -// 3.0 required -impl opc_da_bindings::IOPCItemIO_Impl for Server_Impl { - fn Read( - &self, - count: u32, - item_ids: *const windows::core::PCWSTR, - max_ages: *const u32, - values: *mut *mut windows::Win32::System::Variant::VARIANT, - qualities: *mut *mut u16, - timestamps: *mut *mut windows::Win32::Foundation::FILETIME, - errors: *mut *mut windows::core::HRESULT, - ) -> windows::core::Result<()> { - let item_ids = PointerReader::try_read_array(count, item_ids)?; - let max_ages = PointerReader::try_read_array(count, max_ages)?; - - let result = self.read( - item_ids - .into_iter() - .zip(max_ages) - .map(|(item_id, max_age)| ItemWithMaxAge { item_id, max_age }) - .collect(), - )?; - - PointerWriter::try_write_array_pointer( - &result - .iter() - .map(|vqt| vqt.value.clone().into()) - .collect::>(), - values, - )?; - - PointerWriter::try_write_array_pointer( - &result.iter().map(|vqt| vqt.quality).collect::>(), - qualities, - )?; - - PointerWriter::try_write_array_pointer( - &result - .iter() - .map(|vqt| vqt.timestamp.try_to_native()) - .collect::>>()?, - timestamps, - )?; - - PointerWriter::try_write_array_pointer( - &result.iter().map(|vqt| vqt.error).collect::>(), - errors, - )?; - - Ok(()) - } - - fn WriteVQT( - &self, - count: u32, - item_ids: *const windows::core::PCWSTR, - item_vqt: *const opc_da_bindings::tagOPCITEMVQT, - errors: *mut *mut windows::core::HRESULT, - ) -> windows::core::Result<()> { - let item_ids = PointerReader::try_read_array(count, item_ids)?; - let item_vqt = PointerReader::try_read_array(count, item_vqt)? - .into_iter() - .try_fold(vec![], |mut acc, item| { - acc.push(item.try_into()?); - windows::core::Result::Ok(acc) - })?; - - let result = self.write_vqt( - item_ids - .into_iter() - .zip(item_vqt) - .map(|(item_id, optional_vqt)| ItemOptionalVqt { - item_id, - optional_vqt, - }) - .collect(), - )?; - - PointerWriter::try_write_array_pointer(&result, errors)?; - - Ok(()) - } -} diff --git a/opc_da/src/server/com/utils.rs b/opc_da/src/server/com/utils.rs deleted file mode 100644 index b56c093..0000000 --- a/opc_da/src/server/com/utils.rs +++ /dev/null @@ -1,328 +0,0 @@ -pub struct PointerReader; - -pub struct PointerWriter; - -pub trait TryWritePointer { - type Error; - - fn try_write(value: T, pointer: *mut T) -> Result<(), Self::Error>; -} - -pub trait TryWriteInto { - type Error; - - fn try_write_into(value: T, pointer: R) -> Result<(), Self::Error>; -} - -pub trait TryWriteTo { - type Error; - - fn try_write_to(value: T) -> Result; -} - -pub trait TryWriteArray { - type Error; - - fn try_write_array(values: &[T], pointer: *mut R) -> Result<(), Self::Error>; -} - -pub trait TryWriteArrayPointer { - type Error; - - fn try_write_array_pointer(values: &[T], pointer: *mut *mut R) -> Result<(), Self::Error>; -} - -pub trait TryRead { - type Error; - - fn try_read(pointer: *const T) -> Result; -} - -pub trait TryReadArray { - type Error; - - fn try_read_array(count: u32, pointer: *const T) -> Result, Self::Error>; -} - -impl TryRead for PointerReader { - type Error = windows::core::Error; - - fn try_read(pointer: *const T) -> Result { - if pointer.is_null() { - return Err(windows::core::Error::new( - windows::Win32::Foundation::E_POINTER, - "Null pointer passed for 'pointer'", - )); - } - - Ok(unsafe { pointer.read() }) - } -} - -impl TryWritePointer for PointerWriter { - type Error = windows::core::Error; - - fn try_write(value: T, pointer: *mut T) -> Result<(), Self::Error> { - if pointer.is_null() { - return Err(windows::core::Error::new( - windows::Win32::Foundation::E_POINTER, - "Null pointer passed for 'pointer'", - )); - } - - unsafe { - pointer.write(value); - } - - Ok(()) - } -} - -impl TryWriteInto> - for PointerWriter -{ - type Error = windows::core::Error; - - fn try_write_into(value: T, pointer: windows::core::OutRef<'_, T>) -> Result<(), Self::Error> { - if pointer.is_null() { - return Err(windows::core::Error::new( - windows::Win32::Foundation::E_POINTER, - "Null pointer passed for 'pointer'", - )); - } - - pointer.write(Some(value))?; - - Ok(()) - } -} - -/// Allocates memory for a string and writes it to the provided pointer. -/// -/// # Safety -/// The caller is responsible for freeing the allocated memory using `CoTaskMemFree`. -impl> TryWriteInto for PointerWriter { - type Error = windows::core::Error; - - fn try_write_into(value: T, pointer: *mut windows::core::PWSTR) -> Result<(), Self::Error> { - let p = value - .as_ref() - .encode_utf16() - .chain(core::iter::once(0)) - .collect::>(); - - let ptr = unsafe { - windows::Win32::System::Com::CoTaskMemAlloc(p.len() * core::mem::size_of::()) - }; - - if ptr.is_null() { - return Err(windows::core::Error::new( - windows::Win32::Foundation::E_OUTOFMEMORY, - "Failed to allocate memory for the string", - )); - } - - unsafe { - core::ptr::copy_nonoverlapping(p.as_ptr(), ptr as *mut u16, p.len()); - *pointer = windows::core::PWSTR(ptr as *mut u16); - } - - Ok(()) - } -} - -impl<'a, T: AsRef<[&'a str]>> TryWriteInto for PointerWriter { - type Error = windows::core::Error; - - fn try_write_into( - value: T, - pointer: *mut *mut windows::core::PWSTR, - ) -> Result<(), Self::Error> { - let mut strings = Vec::with_capacity(value.as_ref().len()); - for s in value.as_ref() { - let p = s - .encode_utf16() - .chain(core::iter::once(0)) - .collect::>(); - let ptr = unsafe { - windows::Win32::System::Com::CoTaskMemAlloc(p.len() * core::mem::size_of::()) - }; - - if ptr.is_null() { - return Err(windows::core::Error::new( - windows::Win32::Foundation::E_OUTOFMEMORY, - "Failed to allocate memory for the string", - )); - } - - unsafe { - core::ptr::copy_nonoverlapping(p.as_ptr(), ptr as *mut u16, p.len()); - strings.push(windows::core::PWSTR(ptr as *mut u16)); - } - } - - let ptr = unsafe { - windows::Win32::System::Com::CoTaskMemAlloc( - strings.len() * core::mem::size_of::(), - ) - }; - - if ptr.is_null() { - return Err(windows::core::Error::new( - windows::Win32::Foundation::E_OUTOFMEMORY, - "Failed to allocate memory for the array of strings", - )); - } - - unsafe { - core::ptr::copy_nonoverlapping( - strings.as_ptr(), - ptr as *mut windows::core::PWSTR, - strings.len(), - ); - *pointer = ptr as _; - } - - Ok(()) - } -} - -impl> TryWriteTo for W { - type Error = windows::core::Error; - - fn try_write_to(value: T) -> windows::core::Result<*mut T> { - let ptr: *mut T = core::ptr::null_mut(); - Self::try_write(value, ptr)?; - Ok(ptr) - } -} - -impl> TryWriteTo for PointerWriter { - type Error = windows::core::Error; - - fn try_write_to(value: T) -> windows::core::Result { - let ptr: *mut windows::core::PWSTR = core::ptr::null_mut(); - Self::try_write_into(value, ptr)?; - Ok(unsafe { *ptr }) - } -} - -impl TryReadArray for PointerReader { - type Error = windows::core::Error; - - fn try_read_array(count: u32, pointer: *const T) -> Result, Self::Error> { - if pointer.is_null() { - return Err(windows::core::Error::new( - windows::Win32::Foundation::E_POINTER, - "Null pointer passed for 'pointer'", - )); - } - - let mut result = Vec::with_capacity(count as usize); - unsafe { - for i in 0..count { - result.push(pointer.add(i as usize).read()); - } - } - Ok(result) - } -} - -impl TryWriteArray for PointerWriter { - type Error = windows::core::Error; - - fn try_write_array(values: &[T], pointer: *mut T) -> Result<(), Self::Error> { - if pointer.is_null() { - return Err(windows::core::Error::new( - windows::Win32::Foundation::E_POINTER, - "Null pointer passed for 'pointer'", - )); - } - - unsafe { - core::ptr::copy_nonoverlapping(values.as_ptr(), pointer, values.len()); - } - - Ok(()) - } -} - -impl TryWriteArrayPointer for PointerWriter { - type Error = windows::core::Error; - - fn try_write_array_pointer(values: &[T], pointer: *mut *mut T) -> Result<(), Self::Error> { - if pointer.is_null() { - return Err(windows::core::Error::new( - windows::Win32::Foundation::E_POINTER, - "Null pointer passed for 'pointer'", - )); - } - - let size = core::mem::size_of_val(values); - let ptr = unsafe { windows::Win32::System::Com::CoTaskMemAlloc(size) }; - - if ptr.is_null() { - return Err(windows::core::Error::new( - windows::Win32::Foundation::E_OUTOFMEMORY, - "Failed to allocate memory for the array", - )); - } - - unsafe { - core::ptr::copy_nonoverlapping(values.as_ptr(), ptr as *mut T, values.len()); - *pointer = ptr as *mut T; - } - - Ok(()) - } -} - -impl TryReadArray for PointerReader { - type Error = windows::core::Error; - - fn try_read_array( - count: u32, - pointer: *const windows::core::PWSTR, - ) -> Result, Self::Error> { - let mut result = Vec::with_capacity(count as usize); - unsafe { - for i in 0..count { - let pwstr = pointer.add(i as usize).read(); - if pwstr.is_null() { - return Err(windows::core::Error::new( - windows::Win32::Foundation::E_POINTER, - "Null pointer encountered while reading string", - )); - } - result.push(pwstr.to_string()?); - } - } - - Ok(result) - } -} - -impl TryReadArray for PointerReader { - type Error = windows::core::Error; - - fn try_read_array( - count: u32, - pointer: *const windows::core::PCWSTR, - ) -> Result, Self::Error> { - let mut result = Vec::with_capacity(count as usize); - unsafe { - for i in 0..count { - let pwstr = pointer.add(i as usize).read(); - if pwstr.is_null() { - return Err(windows::core::Error::new( - windows::Win32::Foundation::E_POINTER, - "Null pointer encountered while reading string", - )); - } - result.push(pwstr.to_string()?); - } - } - - Ok(result) - } -} diff --git a/opc_da/src/server/com/variant.rs b/opc_da/src/server/com/variant.rs deleted file mode 100644 index 46b7d6c..0000000 --- a/opc_da/src/server/com/variant.rs +++ /dev/null @@ -1,94 +0,0 @@ -use windows::{Win32::System::Variant::VARIANT, core::BSTR}; - -use super::base::{AccessRight, Quality, Variant}; - -use opc_da_bindings; - -impl Variant { - // get type id - pub fn get_data_type(&self) -> u16 { - match self { - Variant::Empty => windows::Win32::System::Variant::VT_EMPTY, - Variant::Bool(_) => windows::Win32::System::Variant::VT_BOOL, - Variant::String(_) => windows::Win32::System::Variant::VT_BSTR, - Variant::I8(_) => windows::Win32::System::Variant::VT_I1, - Variant::I16(_) => windows::Win32::System::Variant::VT_I2, - Variant::I32(_) => windows::Win32::System::Variant::VT_I4, - Variant::I64(_) => windows::Win32::System::Variant::VT_I8, - Variant::F32(_) => windows::Win32::System::Variant::VT_R4, - Variant::F64(_) => windows::Win32::System::Variant::VT_R8, - Variant::U8(_) => windows::Win32::System::Variant::VT_UI1, - Variant::U16(_) => windows::Win32::System::Variant::VT_UI2, - Variant::U32(_) => windows::Win32::System::Variant::VT_UI4, - Variant::U64(_) => windows::Win32::System::Variant::VT_UI8, - } - .0 - } -} - -impl Quality { - pub fn to_u16(&self) -> u16 { - self.0 - } -} - -impl AccessRight { - pub fn to_u32(&self) -> u32 { - let mut value = 0; - if self.readable { - value |= opc_da_bindings::OPC_READABLE; - } - if self.writable { - value |= opc_da_bindings::OPC_WRITEABLE; - } - value - } -} - -impl From for VARIANT { - fn from(val: Variant) -> Self { - match val { - Variant::Empty => VARIANT::default(), - Variant::Bool(value) => VARIANT::from(value), - Variant::String(value) => VARIANT::from(BSTR::from(value)), - Variant::I8(value) => VARIANT::from(value), - Variant::I16(value) => VARIANT::from(value), - Variant::I32(value) => VARIANT::from(value), - Variant::I64(value) => VARIANT::from(value), - Variant::F32(value) => VARIANT::from(value), - Variant::F64(value) => VARIANT::from(value), - Variant::U8(value) => VARIANT::from(value), - Variant::U16(value) => VARIANT::from(value), - Variant::U32(value) => VARIANT::from(value), - Variant::U64(value) => VARIANT::from(value), - } - } -} - -impl From for Variant { - fn from(value: VARIANT) -> Self { - unsafe { - let value = &value.Anonymous.Anonymous; - match value.vt { - windows::Win32::System::Variant::VT_EMPTY => Variant::Empty, - windows::Win32::System::Variant::VT_BOOL => { - Variant::Bool(value.Anonymous.boolVal.as_bool()) - } - windows::Win32::System::Variant::VT_BSTR => { - Variant::String(value.Anonymous.bstrVal.to_string()) - } - windows::Win32::System::Variant::VT_I1 => Variant::I8(value.Anonymous.cVal), - windows::Win32::System::Variant::VT_I2 => Variant::I16(value.Anonymous.iVal), - windows::Win32::System::Variant::VT_I4 => Variant::I32(value.Anonymous.lVal), - windows::Win32::System::Variant::VT_I8 => Variant::I64(value.Anonymous.llVal), - windows::Win32::System::Variant::VT_R4 => Variant::F32(value.Anonymous.fltVal), - windows::Win32::System::Variant::VT_R8 => Variant::F64(value.Anonymous.dblVal), - windows::Win32::System::Variant::VT_UI1 => Variant::U8(value.Anonymous.bVal), - windows::Win32::System::Variant::VT_UI2 => Variant::U16(value.Anonymous.uiVal), - windows::Win32::System::Variant::VT_UI4 => Variant::U32(value.Anonymous.ulVal), - windows::Win32::System::Variant::VT_UI8 => Variant::U64(value.Anonymous.ullVal), - _ => Variant::Empty, - } - } - } -} diff --git a/opc_da/src/server/mod.rs b/opc_da/src/server/mod.rs deleted file mode 100644 index 8e7f1f4..0000000 --- a/opc_da/src/server/mod.rs +++ /dev/null @@ -1,2 +0,0 @@ -pub mod com; -pub mod traits; diff --git a/opc_da/src/server/traits/def.rs b/opc_da/src/server/traits/def.rs deleted file mode 100644 index 5960096..0000000 --- a/opc_da/src/server/traits/def.rs +++ /dev/null @@ -1,330 +0,0 @@ -use crate::{ - def::ServerStatus, - server::com::{ - base::Variant, - utils::{PointerWriter, TryWriteArray, TryWriteTo}, - }, - utils::{ToNative as _, TryToLocal as _, TryToNative as _}, -}; - -pub struct AvailableProperty { - pub property_id: u32, - pub description: String, - pub data_type: u16, -} - -pub struct ItemPropertyData { - pub property_id: u32, - pub data: Variant, - pub error: windows::core::HRESULT, -} - -pub struct NewItem { - pub new_item_id: String, - pub error: windows::core::HRESULT, -} - -pub struct ItemProperties { - pub error_id: windows::core::HRESULT, - pub item_properties: Vec, -} - -pub struct ItemProperty { - pub data_type: u16, - pub property_id: u32, - pub item_id: String, - pub description: String, - pub value: Variant, - pub error_id: windows::core::HRESULT, -} - -pub enum BrowseFilter { - All, - Branches, - Items, -} - -pub struct BrowseResult { - pub more_elements: bool, - pub continuation_point: Option, - pub elements: Vec, -} - -pub struct BrowseElement { - pub name: String, - pub item_id: String, - pub flag_value: u32, - pub item_properties: ItemProperties, -} - -pub enum NamespaceType { - Flat, - Hierarchical, -} - -pub enum BrowseDirection { - Up, - Down, - To(String), -} - -pub enum BrowseType { - Branch, - Leaf, - Flat, -} - -pub struct ItemWithMaxAge { - pub item_id: String, - pub max_age: u32, -} - -pub struct Vqt { - pub value: Variant, - pub quality: u16, - pub timestamp: std::time::SystemTime, -} - -pub struct ItemVqt { - pub value: Variant, - pub quality: Option, - pub timestamp: Option, -} - -pub struct VqtWithError { - pub value: Variant, - pub quality: u16, - pub timestamp: std::time::SystemTime, - pub error: windows::core::HRESULT, -} - -pub struct ItemOptionalVqt { - pub item_id: String, - pub optional_vqt: ItemVqt, -} - -pub struct GroupInfo { - pub server_group: u32, - pub revised_update_rate: u32, - pub unknown: windows::core::IUnknown, -} - -pub struct FormatEtc {} - -pub struct StorageMedium {} - -pub enum DataSource { - Cache, - Device, -} - -pub struct ItemDef {} - -pub struct ItemResult {} - -pub struct ItemState {} - -impl TryFrom for opc_da_bindings::tagOPCITEMPROPERTIES { - type Error = windows::core::Error; - - fn try_from(value: ItemProperties) -> Result { - let result = opc_da_bindings::tagOPCITEMPROPERTIES { - hrErrorID: value.error_id, - dwNumProperties: value.item_properties.len() as u32, - pItemProperties: core::ptr::null_mut(), - dwReserved: 0, - }; - - PointerWriter::try_write_array( - &value - .item_properties - .into_iter() - .map(|item_property| match item_property.try_into() { - Ok(item_property) => item_property, - Err(error) => opc_da_bindings::tagOPCITEMPROPERTY { - hrErrorID: (error as windows::core::Error).code(), - ..Default::default() - }, - }) - .collect::>(), - result.pItemProperties, - )?; - - Ok(result) - } -} - -impl TryFrom for opc_da_bindings::tagOPCITEMPROPERTY { - type Error = windows::core::Error; - - fn try_from(value: ItemProperty) -> Result { - Ok(opc_da_bindings::tagOPCITEMPROPERTY { - vtDataType: value.data_type, - wReserved: 0, - dwPropertyID: value.property_id, - szItemID: PointerWriter::try_write_to(&value.item_id)?, - szDescription: PointerWriter::try_write_to(&value.description)?, - vValue: value.value.into(), - hrErrorID: value.error_id, - dwReserved: 0, - }) - } -} - -impl From for opc_da_bindings::tagOPCBROWSEFILTER { - fn from(value: BrowseFilter) -> Self { - match value { - BrowseFilter::All => opc_da_bindings::OPC_BROWSE_FILTER_ALL, - BrowseFilter::Branches => opc_da_bindings::OPC_BROWSE_FILTER_BRANCHES, - BrowseFilter::Items => opc_da_bindings::OPC_BROWSE_FILTER_ITEMS, - } - } -} - -impl TryFrom for BrowseFilter { - type Error = windows::core::Error; - - fn try_from(value: opc_da_bindings::tagOPCBROWSEFILTER) -> Result { - match value { - opc_da_bindings::OPC_BROWSE_FILTER_ALL => Ok(BrowseFilter::All), - opc_da_bindings::OPC_BROWSE_FILTER_BRANCHES => Ok(BrowseFilter::Branches), - opc_da_bindings::OPC_BROWSE_FILTER_ITEMS => Ok(BrowseFilter::Items), - _ => Err(windows::core::Error::new( - windows::Win32::Foundation::E_INVALIDARG, - "Invalid BrowseFilter", - )), - } - } -} - -impl TryFrom for opc_da_bindings::tagOPCBROWSEELEMENT { - type Error = windows::core::Error; - - fn try_from(value: BrowseElement) -> Result { - Ok(opc_da_bindings::tagOPCBROWSEELEMENT { - szName: PointerWriter::try_write_to(&value.name)?, - szItemID: PointerWriter::try_write_to(&value.item_id)?, - dwFlagValue: value.flag_value, - dwReserved: 0, - ItemProperties: value.item_properties.try_into()?, - }) - } -} - -impl From for opc_da_bindings::tagOPCNAMESPACETYPE { - fn from(value: NamespaceType) -> Self { - match value { - NamespaceType::Flat => opc_da_bindings::OPC_NS_FLAT, - NamespaceType::Hierarchical => opc_da_bindings::OPC_NS_HIERARCHIAL, - } - } -} - -impl TryFrom for NamespaceType { - type Error = windows::core::Error; - - fn try_from(value: opc_da_bindings::tagOPCNAMESPACETYPE) -> Result { - match value { - opc_da_bindings::OPC_NS_FLAT => Ok(NamespaceType::Flat), - opc_da_bindings::OPC_NS_HIERARCHIAL => Ok(NamespaceType::Hierarchical), - _ => Err(windows::core::Error::new( - windows::Win32::Foundation::E_INVALIDARG, - "Invalid NamespaceType", - )), - } - } -} - -impl TryFrom<(opc_da_bindings::tagOPCBROWSEDIRECTION, String)> for BrowseDirection { - type Error = windows::core::Error; - - fn try_from( - value: (opc_da_bindings::tagOPCBROWSEDIRECTION, String), - ) -> Result { - match value { - (opc_da_bindings::OPC_BROWSE_UP, _) => Ok(BrowseDirection::Up), - (opc_da_bindings::OPC_BROWSE_DOWN, _) => Ok(BrowseDirection::Down), - (opc_da_bindings::OPC_BROWSE_TO, name) => Ok(BrowseDirection::To(name)), - _ => Err(windows::core::Error::new( - windows::Win32::Foundation::E_INVALIDARG, - "Invalid BrowseDirection", - )), - } - } -} - -impl From for (opc_da_bindings::tagOPCBROWSEDIRECTION, String) { - fn from(value: BrowseDirection) -> Self { - match value { - BrowseDirection::Up => (opc_da_bindings::OPC_BROWSE_UP, String::new()), - BrowseDirection::Down => (opc_da_bindings::OPC_BROWSE_DOWN, String::new()), - BrowseDirection::To(name) => (opc_da_bindings::OPC_BROWSE_TO, name), - } - } -} - -impl TryFrom for BrowseType { - type Error = windows::core::Error; - - fn try_from(value: opc_da_bindings::tagOPCBROWSETYPE) -> Result { - match value { - opc_da_bindings::OPC_BRANCH => Ok(BrowseType::Branch), - opc_da_bindings::OPC_LEAF => Ok(BrowseType::Leaf), - opc_da_bindings::OPC_FLAT => Ok(BrowseType::Flat), - _ => Err(windows::core::Error::new( - windows::Win32::Foundation::E_INVALIDARG, - "Invalid BrowseFilter", - )), - } - } -} - -impl From for opc_da_bindings::tagOPCBROWSETYPE { - fn from(value: BrowseType) -> Self { - match value { - BrowseType::Branch => opc_da_bindings::OPC_BRANCH, - BrowseType::Leaf => opc_da_bindings::OPC_LEAF, - BrowseType::Flat => opc_da_bindings::OPC_FLAT, - } - } -} - -impl TryFrom for ItemVqt { - type Error = windows::core::Error; - - fn try_from(value: opc_da_bindings::tagOPCITEMVQT) -> Result { - Ok(ItemVqt { - value: value.vDataValue.into(), - quality: if value.bQualitySpecified.as_bool() { - Some(value.wQuality) - } else { - None - }, - timestamp: if value.bTimeStampSpecified.as_bool() { - Some(value.ftTimeStamp.try_to_local()?) - } else { - None - }, - }) - } -} - -impl TryFrom for opc_da_bindings::tagOPCSERVERSTATUS { - type Error = windows::core::Error; - - fn try_from(value: ServerStatus) -> Result { - Ok(Self { - ftStartTime: value.start_time.try_to_native()?, - ftCurrentTime: value.current_time.try_to_native()?, - ftLastUpdateTime: value.last_update_time.try_to_native()?, - dwServerState: value.server_state.to_native(), - dwGroupCount: value.group_count, - dwBandWidth: value.band_width, - wMajorVersion: value.major_version, - wMinorVersion: value.minor_version, - wBuildNumber: value.build_number, - szVendorInfo: PointerWriter::try_write_to(&value.vendor_info)?, - wReserved: 0, - }) - } -} diff --git a/opc_da/src/server/traits/group.rs b/opc_da/src/server/traits/group.rs deleted file mode 100644 index 57a9c55..0000000 --- a/opc_da/src/server/traits/group.rs +++ /dev/null @@ -1,318 +0,0 @@ -pub trait GroupTrait { - fn add_items( - &self, - items: &[opc_da_bindings::tagOPCITEMDEF], - results: &mut [opc_da_bindings::tagOPCITEMRESULT], - errors: &mut [windows::core::HRESULT], - ) -> windows::core::Result<()>; - - fn validate_items( - &self, - items: &[opc_da_bindings::tagOPCITEMDEF], - blob_update: windows_core::BOOL, - validation_results: &mut [opc_da_bindings::tagOPCITEMRESULT], - errors: &mut [windows::core::HRESULT], - ) -> windows::core::Result<()>; - - fn remove_items( - &self, - item_server_handles: &[u32], - errors: &mut [windows::core::HRESULT], - ) -> windows::core::Result<()>; - - fn set_active_state( - &self, - item_server_handles: &[u32], - active: windows_core::BOOL, - errors: &mut [windows::core::HRESULT], - ) -> windows::core::Result<()>; - - fn set_client_handles( - &self, - item_server_handles: &[u32], - handle_client: &[u32], - errors: &mut [windows::core::HRESULT], - ) -> windows::core::Result<()>; - - fn set_data_types( - &self, - item_server_handles: &[u32], - requested_data_types: &[u16], - errors: &mut [windows::core::HRESULT], - ) -> windows::core::Result<()>; - - fn create_enumerator( - &self, - reference_interface_id: &windows::core::GUID, - ) -> windows::core::Result; - - #[allow(clippy::too_many_arguments)] - fn get_state( - &self, - update_rate: &mut u32, - active: &mut windows_core::BOOL, - name: &mut windows::core::PWSTR, - time_bias: &mut i32, - percent_deadband: &mut f32, - locale_id: &mut u32, - group_client_handle: &mut u32, - item_server_handles_group: &mut u32, - ) -> windows::core::Result<()>; - - #[allow(clippy::too_many_arguments)] - fn set_state( - &self, - requested_update_rate: &u32, - revised_update_rate: &mut u32, - active: &windows_core::BOOL, - time_bias: &i32, - percent_deadband: &f32, - locale_id: &u32, - group_client_handle: &u32, - ) -> windows::core::Result<()>; - - fn set_name(&self, name: &windows::core::PCWSTR) -> windows::core::Result<()>; - - fn clone_group( - &self, - name: &windows::core::PCWSTR, - reference_interface_id: &windows::core::GUID, - ) -> windows::core::Result; - - fn set_keep_alive(&self, keep_alive_time: u32) -> windows::core::Result; - - fn get_keep_alive(&self) -> windows::core::Result; - - fn get_public_group_state(&self) -> windows::core::Result; - - fn move_to_public(&self) -> windows::core::Result<()>; - - fn read( - &self, - source: opc_da_bindings::tagOPCDATASOURCE, - item_server_handles: &[u32], - item_values: &mut [opc_da_bindings::tagOPCITEMSTATE], - errors: &mut [windows::core::HRESULT], - ) -> windows::core::Result<()>; - - fn write( - &self, - item_server_handles: &[u32], - item_values: &[windows::Win32::System::Variant::VARIANT], - errors: &mut [windows::core::HRESULT], - ) -> windows::core::Result<()>; - - fn read_max_age( - &self, - item_server_handles: &[u32], - max_age: &[u32], - values: &mut [windows::Win32::System::Variant::VARIANT], - qualities: &mut [u16], - timestamps: &mut [windows::Win32::Foundation::FILETIME], - errors: &mut [windows::core::HRESULT], - ) -> windows::core::Result<()>; - - fn write_vqt( - &self, - count: u32, - item_server_handles: &[u32], - item_vqt: &[opc_da_bindings::tagOPCITEMVQT], - errors: &mut [windows::core::HRESULT], - ) -> windows::core::Result<()>; - - fn read2( - &self, - item_server_handles: &[u32], - transaction_id: u32, - cancel_id: &mut u32, - errors: &mut [windows::core::HRESULT], - ) -> windows::core::Result<()>; - - fn write2( - &self, - count: u32, - item_server_handles: &[u32], - item_values: &[windows::Win32::System::Variant::VARIANT], - transaction_id: u32, - cancel_id: &mut u32, - errors: &mut [windows::core::HRESULT], - ) -> windows::core::Result<()>; - - fn refresh2( - &self, - source: opc_da_bindings::tagOPCDATASOURCE, - transaction_id: u32, - ) -> windows::core::Result; - - fn cancel2(&self, cancel_id: u32) -> windows::core::Result<()>; - - fn set_enable(&self, enable: windows_core::BOOL) -> windows::core::Result<()>; - - fn get_enable(&self) -> windows::core::Result; - - fn read_max_age2( - &self, - item_server_handles: &[u32], - max_age: &[u32], - transaction_id: u32, - cancel_id: &mut u32, - errors: &mut [windows::core::HRESULT], - ) -> windows::core::Result<()>; - - fn write_vqt2( - &self, - item_server_handles: &[u32], - item_vqt: &[opc_da_bindings::tagOPCITEMVQT], - transaction_id: u32, - cancel_id: &mut u32, - errors: &mut [windows::core::HRESULT], - ) -> windows::core::Result<()>; - - fn refresh_max_age(&self, max_age: u32, transaction_id: u32) -> windows::core::Result; - - fn set_item_deadband( - &self, - item_server_handles: &[u32], - percent_deadband: &[f32], - errors: &mut [windows::core::HRESULT], - ) -> windows::core::Result<()>; - - fn get_item_deadband( - &self, - item_server_handles: &[u32], - percent_deadband: &mut [f32], - errors: &mut [windows::core::HRESULT], - ) -> windows::core::Result<()>; - - fn clear_item_deadband( - &self, - item_server_handles: &[u32], - errors: &mut [windows::core::HRESULT], - ) -> windows::core::Result<()>; - - fn set_item_sampling_rate( - &self, - count: u32, - item_server_handles: &[u32], - requested_sampling_rate: &[u32], - revised_sampling_rate: &mut [u32], - errors: &mut [windows::core::HRESULT], - ) -> windows::core::Result<()>; - - fn get_item_sampling_rate( - &self, - item_server_handles: &[u32], - sampling_rate: &mut [u32], - errors: &mut [windows::core::HRESULT], - ) -> windows::core::Result<()>; - - fn clear_item_sampling_rate( - &self, - item_server_handles: &[u32], - errors: &mut [windows::core::HRESULT], - ) -> windows::core::Result<()>; - - fn set_item_buffer_enable( - &self, - item_server_handles: &[u32], - penable: &windows_core::BOOL, - errors: &mut [windows::core::HRESULT], - ) -> windows::core::Result<()>; - - fn get_item_buffer_enable( - &self, - item_server_handles: &[u32], - enable: &mut [windows_core::BOOL], - errors: &mut [windows::core::HRESULT], - ) -> windows::core::Result<()>; - - fn enum_connection_points( - &self, - ) -> windows::core::Result; - - fn find_connection_point( - &self, - reference_interface_id: &windows::core::GUID, - ) -> windows::core::Result; - - fn read3( - &self, - connection: u32, - source: opc_da_bindings::tagOPCDATASOURCE, - item_server_handles: &[u32], - transaction_id: &mut u32, - errors: &mut [windows::core::HRESULT], - ) -> windows::core::Result<()>; - - fn write3( - &self, - connection: u32, - item_server_handles: &[u32], - item_values: &[windows::Win32::System::Variant::VARIANT], - transaction_id: &mut u32, - errors: &mut [windows::core::HRESULT], - ) -> windows::core::Result<()>; - - fn refresh( - &self, - connection: u32, - source: opc_da_bindings::tagOPCDATASOURCE, - ) -> windows::core::Result; - - fn cancel(&self, transaction_id: u32) -> windows::core::Result<()>; - - fn get_data( - &self, - format_etc_in: &windows::Win32::System::Com::FORMATETC, - ) -> windows::core::Result; - - fn get_data_here( - &self, - format_etc_in: &windows::Win32::System::Com::FORMATETC, - storage_medium: &mut windows::Win32::System::Com::STGMEDIUM, - ) -> windows::core::Result<()>; - - fn query_get_data( - &self, - format_etc_in: &windows::Win32::System::Com::FORMATETC, - ) -> windows::core::HRESULT; - - fn get_canonical_format_etc( - &self, - format_etc_in: &windows::Win32::System::Com::FORMATETC, - format_etc_out: &mut windows::Win32::System::Com::FORMATETC, - ) -> windows::core::HRESULT; - - fn set_data( - &self, - format_etc_in: &windows::Win32::System::Com::FORMATETC, - medium: &windows::Win32::System::Com::STGMEDIUM, - release: windows_core::BOOL, - ) -> windows::core::Result<()>; - - fn enum_format_etc( - &self, - direction: u32, - ) -> windows::core::Result; - - /// Establishes an advisory connection. - /// - /// # Arguments - /// * `sink` - The sink interface. If None, any existing connection will be removed. - /// - /// # Returns - /// * The connection token if sink is Some and connection is established - /// * Ok(0) if sink is None (indicating no connection) - /// * An error if the operation fails - fn data_advise( - &self, - format_etc_in: &windows::Win32::System::Com::FORMATETC, - adv: u32, - sink: windows::core::Ref<'_, windows::Win32::System::Com::IAdviseSink>, - ) -> windows::core::Result; - - fn data_unadvise(&self, connection: u32) -> windows::core::Result<()>; - - fn enum_data_advise(&self) - -> windows::core::Result; -} diff --git a/opc_da/src/server/traits/item.rs b/opc_da/src/server/traits/item.rs deleted file mode 100644 index 0ec23fb..0000000 --- a/opc_da/src/server/traits/item.rs +++ /dev/null @@ -1 +0,0 @@ -pub trait ItemTrait {} diff --git a/opc_da/src/server/traits/mod.rs b/opc_da/src/server/traits/mod.rs deleted file mode 100644 index f53bc47..0000000 --- a/opc_da/src/server/traits/mod.rs +++ /dev/null @@ -1,9 +0,0 @@ -mod def; -mod group; -mod item; -mod server; - -pub use def::*; -pub use group::*; -pub use item::*; -pub use server::*; diff --git a/opc_da/src/server/traits/server.rs b/opc_da/src/server/traits/server.rs deleted file mode 100644 index 5e4604e..0000000 --- a/opc_da/src/server/traits/server.rs +++ /dev/null @@ -1,252 +0,0 @@ -use crate::def::{EnumScope, ServerStatus}; - -use super::def::*; - -/// Server trait -/// -/// This trait defines the methods that a opc da server must implement to be used by the opc da client. -pub trait ServerTrait { - /// Sets the locale ID to be used for string conversions. - /// - /// Implements the `IOPCCommon::SetLocaleID` method. - /// - /// # Arguments - /// * `locale_id` - The locale ID to set - /// - /// # Returns - /// An error if the locale ID is not supported - fn set_locale_id(&self, locale_id: u32) -> windows::core::Result<()>; - - /// Returns the current locale ID. - /// - /// Implements the `IOPCCommon::GetLocaleID` method. - /// - /// # Returns - /// The current locale ID - fn get_locale_id(&self) -> windows::core::Result; - - /// Returns the list of available locale IDs. - /// - /// Implements the `IOPCCommon::QueryAvailableLocaleIDs` method. - /// - /// # Returns - /// The list of available locale IDs - fn query_available_locale_ids(&self) -> windows::core::Result>; - - /// Returns the error string for the given error code. - /// - /// Implements the `IOPCCommon::GetErrorString` method. - /// - /// # Arguments - /// * `error` - The error code - /// - /// # Returns - /// The error string for the given error code - fn get_error_string(&self, error: i32) -> windows::core::Result; - - /// Sets the name of the client application. - /// - /// Implements the `IOPCCommon::SetClientName` method. - /// - /// # Arguments - /// * `name` - The client application name - /// - /// # Returns - /// An error if the operation fails - fn set_client_name(&self, name: String) -> windows::core::Result<()>; - - /// Returns the name of the client application. - /// - /// Implements the `IConnectionPointContainer::EnumConnectionPoints` method. - /// - /// # Returns - /// - /// A result containing a vector of connection points - fn enum_connection_points( - &self, - ) -> windows::core::Result>; - - /// Returns the connection point for the given reference interface ID. - /// - /// Implements the `IConnectionPointContainer::FindConnectionPoint` method. - /// - /// # Arguments - /// * `reference_interface_id` - The reference interface ID - /// - /// # Returns - /// The connection point - fn find_connection_point( - &self, - reference_interface_id: *const windows::core::GUID, - ) -> windows::core::Result; - - /// Returns the list of available properties for the given item ID. - /// - /// Implements the `IOPCBrowse::QueryAvailableProperties` method. - /// - /// # Arguments - /// * `item_id` - The item ID - /// - /// # Returns - /// The list of available properties - fn query_available_properties( - &self, - item_id: String, - ) -> windows::core::Result>; - - /// Returns the properties for the given item ID. - /// - /// Implements the `IOPCItemProperties::GetItemProperties` method. - /// - /// # Arguments - /// * `item_id` - The item ID - /// * `property_ids` - The list of property IDs - /// - /// # Returns - /// The properties for the given item ID - fn get_item_properties( - &self, - item_id: String, - property_ids: Vec, - ) -> windows::core::Result>; - - /// Lookup the item IDs for the given item ID and property IDs. - /// - /// Implements the `IOPCBrowse::LookupItemIDs` method. - /// - /// # Arguments - /// * `item_id` - The item ID - /// * `property_ids` - The list of property IDs - /// - /// # Returns - /// The item IDs for the given item ID and property IDs - fn lookup_item_ids( - &self, - item_id: String, - property_ids: Vec, - ) -> windows::core::Result>; - - /// Returns the properties for the given item IDs. - /// - /// Implements the `IOPCItemProperties::GetProperties` method. - /// - /// # Arguments - /// * `item_ids` - The list of item IDs - /// * `return_property_values` - Whether to return property values - /// * `property_ids` - The list of property IDs - /// - /// # Returns - /// The properties for the given item IDs - fn get_properties( - &self, - item_ids: Vec, - return_property_values: bool, - property_ids: Vec, - ) -> windows::core::Result>; - - /// Browse the server for items. - /// - /// Implements the `IOPCBrowse::Browse` method. - /// - /// # Arguments - /// * `item_id` - The item ID - /// * `continuation_point` - The continuation point - /// * `max_elements_returned` - The maximum number of elements to return - /// * `browse_filter` - The browse filter - /// * `element_name_filter` - The element name filter - /// * `vendor_filter` - The vendor filter - /// * `return_all_properties` - Whether to return all properties - /// * `return_property_values` - Whether to return property values - /// * `property_ids` - The list of property IDs - /// - /// # Returns - /// The browse result - #[allow(clippy::too_many_arguments)] - fn browse( - &self, - item_id: String, - continuation_point: Option, - max_elements_returned: u32, - browse_filter: BrowseFilter, - element_name_filter: String, - vendor_filter: String, - return_all_properties: bool, - return_property_values: bool, - property_ids: Vec, - ) -> windows::core::Result; - - /// Get the public group by name. - /// - /// Implements the `IOPCServerPublicGroups::GetPublicGroupByName` method. - /// - /// # Arguments - /// * `name` - The name of the public group - /// * `reference_interface_id` - The reference interface ID - /// - /// # Returns - /// The public group - fn get_public_group_by_name( - &self, - name: String, - reference_interface_id: u128, - ) -> windows::core::Result; - - fn remove_public_group(&self, server_group: u32, force: bool) -> windows::core::Result<()>; - - fn query_organization(&self) -> windows::core::Result; - - fn change_browse_position( - &self, - browse_direction: BrowseDirection, - ) -> windows::core::Result<()>; - - fn browse_opc_item_ids( - &self, - browse_filter_type: BrowseType, - filter_criteria: String, - variant_data_type_filter: u16, - access_rights_filter: u32, - ) -> windows::core::Result; - - fn get_item_id(&self, item_data_id: String) -> windows::core::Result; - - fn browse_access_paths(&self, item_id: String) -> windows::core::Result>; - - fn read(&self, items: Vec) -> windows::core::Result>; - - fn write_vqt( - &self, - items: Vec, - ) -> windows::core::Result>; - - #[allow(clippy::too_many_arguments)] - fn add_group( - &self, - name: String, - active: bool, - requested_update_rate: u32, - client_group: u32, - time_bias: Option, - percent_deadband: Option, - locale_id: u32, - reference_interface_id: Option, - ) -> windows::core::Result; - - fn get_error_string_locale(&self, error: i32, locale: u32) -> windows::core::Result; - - fn get_group_by_name( - &self, - name: String, - reference_interface_id: Option, - ) -> windows::core::Result; - - fn get_status(&self) -> windows::core::Result; - - fn remove_group(&self, server_group: u32, force: bool) -> windows::core::Result<()>; - - fn create_group_enumerator( - &self, - scope: EnumScope, - reference_interface_id: Option, - ) -> windows::core::Result; -} diff --git a/opc_da/src/utils/memory.rs b/opc_da/src/utils/memory.rs deleted file mode 100644 index c29f4bf..0000000 --- a/opc_da/src/utils/memory.rs +++ /dev/null @@ -1,485 +0,0 @@ -//! Memory management utilities for the OPC DA client. -//! -//! This module provides safe wrappers around COM memory allocations and arrays. -//! -//! It includes three main types: -//! - `RemoteArray` for managing arrays allocated by COM. -//! - `RemotePointer` for managing single values allocated by COM. -//! - `LocalPointer` for managing local memory that needs to be passed to COM functions. - -use windows::{ - Win32::System::Com::{CoTaskMemAlloc, CoTaskMemFree}, - core::PWSTR, -}; - -/// A safe wrapper around arrays allocated by COM. -/// -/// This struct ensures proper cleanup of COM-allocated memory when dropped. -/// It provides safe access to the underlying array through slices. -#[derive(Debug, Clone, PartialEq)] -pub struct RemoteArray { - pointer: RemotePointer, - len: u32, -} - -impl RemoteArray { - /// Creates a new `RemoteArray` with the specified length. - /// The underlying pointer is initialized to null. - #[inline(always)] - pub fn new(len: u32) -> Self { - Self { - pointer: RemotePointer::null(), - len, - } - } - - /// Creates a `RemoteArray` from a raw pointer and length. - /// - /// # Safety - /// The caller must ensure that the pointer is valid and points to a COM-allocated array. - #[inline(always)] - pub(crate) fn from_mut_ptr(pointer: *mut T, len: u32) -> Self { - Self { - pointer: RemotePointer::from_raw(pointer), - len, - } - } - - /// Creates a `RemoteArray` from a constant pointer and length. - /// - /// # Safety - /// The caller must ensure that the pointer is valid and points to a COM-allocated array. - #[inline(always)] - pub(crate) fn from_ptr(pointer: *const T, len: u32) -> Self { - Self { - pointer: RemotePointer::from_raw(pointer as *mut T), - len, - } - } - - /// Creates an empty `RemoteArray`. - #[inline(always)] - pub fn empty() -> Self { - Self { - pointer: RemotePointer::null(), - len: 0, - } - } - - /// Returns a mutable pointer to the array pointer. - /// - /// This is useful when calling COM functions that output an array via a pointer to a pointer. - #[inline(always)] - pub fn as_mut_ptr(&mut self) -> *mut *mut T { - self.pointer.as_mut_ptr() - } - - /// Returns a slice to the underlying array. - /// - /// # Safety - /// The caller must ensure that the `pointer` is valid for reads and points to an array of `len` elements. - #[inline(always)] - pub fn as_slice(&self) -> &[T] { - if self.pointer.inner.is_null() || self.len == 0 { - return &[]; - } - - let len = usize::try_from(self.len).unwrap_or(0); - - // Pointer and length are guaranteed to be valid - unsafe { core::slice::from_raw_parts(self.pointer.inner, len) } - } - - /// Returns a mutable slice to the underlying array. - /// - /// # Safety - /// The caller must ensure that the `pointer` is valid for reads and writes and points to an array of `len` elements. - #[inline(always)] - pub fn as_mut_slice(&mut self) -> &mut [T] { - if self.pointer.inner.is_null() || self.len == 0 { - return &mut []; - } - - let len = usize::try_from(self.len).unwrap_or(0); - - // Pointer and length are guaranteed to be valid - unsafe { core::slice::from_raw_parts_mut(self.pointer.inner, len) } - } - - /// Returns the length of the array. - #[inline(always)] - pub fn len(&self) -> u32 { - if self.pointer.inner.is_null() { - return 0; - } - - self.len - } - - /// Checks if the array is empty. - #[inline(always)] - pub fn is_empty(&self) -> bool { - self.len == 0 || self.pointer.inner.is_null() - } - - /// Returns a mutable pointer to the length. - /// - /// This is useful when calling COM functions that output the length via a pointer. - #[inline(always)] - pub fn as_mut_len_ptr(&mut self) -> *mut u32 { - &mut self.len - } - - /// Sets the length of the array. - /// - /// # Safety - /// The caller must ensure that the new length is valid for the underlying array. - #[inline(always)] - pub(crate) unsafe fn set_len(&mut self, len: u32) { - self.len = len; - } - - pub fn into_vec(self) -> Vec> { - self.as_slice() - .iter() - .map(|v| RemotePointer::from_raw(v as *const T as *mut T)) - .collect() - } -} - -impl Default for RemoteArray { - /// Creates an empty `RemoteArray` by default. - #[inline(always)] - fn default() -> Self { - Self::empty() - } -} - -/// A safe wrapper around a pointer allocated by COM. -/// -/// This struct ensures proper cleanup of COM-allocated memory when dropped. -/// It provides methods to access the underlying pointer. -#[repr(transparent)] -#[derive(Debug, Clone, PartialEq)] -pub struct RemotePointer { - inner: *mut T, -} - -impl RemotePointer { - /// Creates a new `RemotePointer` initialized to null. - #[inline(always)] - pub fn null() -> Self { - Self { - inner: core::ptr::null_mut(), - } - } - - /// Returns a mutable pointer to the inner pointer. - /// - /// Useful for COM functions that output data via a pointer to a pointer. - #[inline(always)] - pub(crate) fn from_raw(pointer: *mut T) -> Self { - Self { inner: pointer } - } - - // pub(crate) fn copy(value: &T) -> Self { - // let pointer = unsafe { CoTaskMemAlloc(std::mem::size_of::()) }; - // unsafe { - // core::ptr::copy_nonoverlapping(value, pointer as _, 1); - // } - // Self { - // inner: pointer as _, - // } - // } - - pub(crate) fn copy_slice(value: &[T]) -> Self { - let pointer = unsafe { CoTaskMemAlloc(core::mem::size_of_val(value)) }; - unsafe { - core::ptr::copy_nonoverlapping(value.as_ptr(), pointer as _, value.len()); - } - Self { - inner: pointer as _, - } - } - - #[inline(always)] - pub fn as_mut_ptr(&mut self) -> *mut *mut T { - &mut self.inner - } - - /// Returns an `Option` referencing the inner value if it is not null. - /// - /// # Safety - /// The caller must ensure that the inner pointer is valid for reads. - #[inline(always)] - pub fn as_ref(&self) -> Option<&T> { - // Pointer is guaranteed to be valid - unsafe { self.inner.as_ref() } - } - - #[inline(always)] - pub fn ok(&self) -> windows::core::Result<&T> { - // Pointer is guaranteed to be valid - unsafe { self.inner.as_ref() }.ok_or_else(|| { - windows::core::Error::new(windows::Win32::Foundation::E_POINTER, "Pointer is null") - }) - } - - #[inline(always)] - pub fn from_option>>(value: Option) -> Self { - match value { - Some(value) => value.into(), - None => Self::null(), - } - } -} - -impl Default for RemotePointer { - /// Creates a new `RemotePointer` initialized to null by default. - #[inline(always)] - fn default() -> Self { - Self::null() - } -} - -impl From for RemotePointer { - /// Converts a `PWSTR` to a `RemotePointer`. - #[inline(always)] - fn from(value: PWSTR) -> Self { - Self { - inner: value.as_ptr(), - } - } -} - -impl From<&str> for RemotePointer { - /// Converts a string slice to a `RemotePointer`. - #[inline(always)] - fn from(value: &str) -> Self { - Self::copy_slice(&value.encode_utf16().chain(Some(0)).collect::>()) - } -} - -impl TryFrom> for String { - type Error = windows::core::Error; - - /// Attempts to convert a `RemotePointer` to a `String`. - /// - /// # Errors - /// Returns an error if the pointer is null or if the string conversion fails. - #[inline(always)] - fn try_from(value: RemotePointer) -> Result { - if value.inner.is_null() { - return Err(windows::Win32::Foundation::E_POINTER.into()); - } - - // Has checked for null pointer - Ok(unsafe { PWSTR(value.inner).to_string() }?) - } -} - -impl TryFrom> for Option { - type Error = windows::core::Error; - - /// Attempts to convert a `RemotePointer` to an `Option`. - /// - /// # Errors - /// Returns an error if the string conversion fails. - #[inline(always)] - fn try_from(value: RemotePointer) -> Result { - if value.inner.is_null() { - return Ok(None); - } - - // Has checked for null pointer - Ok(Some(unsafe { PWSTR(value.inner).to_string() }?)) - } -} - -impl RemotePointer { - /// Returns a mutable pointer to a `PWSTR`. - #[inline(always)] - pub fn as_mut_pwstr_ptr(&mut self) -> *mut PWSTR { - &mut self.inner as *mut *mut u16 as *mut PWSTR - } -} - -impl Drop for RemotePointer { - /// Drops the `RemotePointer`, freeing the COM-allocated memory. - #[inline(always)] - fn drop(&mut self) { - if !self.inner.is_null() { - unsafe { - CoTaskMemFree(Some(self.inner as _)); - } - } - } -} - -/// A safe wrapper around locally allocated memory needing to be passed to COM functions. -/// -/// This struct is useful for preparing data to be read by COM functions. -pub struct LocalPointer { - inner: Option>, -} - -impl LocalPointer { - /// Creates a new `LocalPointer` from an optional value. - #[inline(always)] - pub fn new(value: Option) -> Self { - Self { - inner: value.map(|v| Box::new(v)), - } - } - - /// Creates a `LocalPointer` from a boxed value. - #[inline(always)] - pub fn from_box(value: Box) -> Self { - Self { inner: Some(value) } - } - - #[inline(always)] - pub fn from_option>>(value: Option) -> Self { - match value { - Some(value) => value.into(), - None => Self::new(None), - } - } - - /// Returns a constant pointer to the inner value. - #[inline(always)] - pub fn as_ptr(&self) -> *const T { - match &self.inner { - Some(value) => value.as_ref() as *const T, - None => std::ptr::null_mut(), - } - } - - /// Returns a mutable pointer to the inner value. - #[inline(always)] - pub fn as_mut_ptr(&mut self) -> *mut T { - match &mut self.inner { - Some(value) => value.as_mut() as *mut T, - None => std::ptr::null_mut(), - } - } - - /// Consumes the `LocalPointer`, returning the inner value if it exists. - #[inline(always)] - pub fn into_inner(self) -> Option { - self.inner.map(|v| *v) - } - - /// Returns a reference to the inner value if it exists. - #[inline(always)] - pub fn inner(&self) -> Option<&T> { - self.inner.as_ref().map(|v| v.as_ref()) - } -} - -// Implementations for string handling - -impl> From for LocalPointer> { - /// Converts a string slice to a `LocalPointer` containing a UTF-16 encoded null-terminated string. - #[inline(always)] - fn from(s: S) -> Self { - Self::new(Some(s.as_ref().encode_utf16().chain(Some(0)).collect())) - } -} - -impl From<&[String]> for LocalPointer>> { - /// Converts a slice of `String`s to a `LocalPointer` containing vectors of UTF-16 encoded null-terminated strings. - #[inline(always)] - fn from(values: &[String]) -> Self { - Self::new(Some( - values - .iter() - .map(|s| s.encode_utf16().chain(Some(0)).collect()) - .collect(), - )) - } -} - -impl LocalPointer> { - /// Returns the length of the inner vector. - #[inline(always)] - pub fn len(&self) -> usize { - match &self.inner { - Some(values) => values.len(), - None => 0, - } - } - - /// Checks if the inner vector is empty. - #[inline(always)] - pub fn is_empty(&self) -> bool { - match &self.inner { - Some(values) => values.is_empty(), - None => true, - } - } - - /// Returns a constant pointer to the inner array. - #[inline(always)] - pub fn as_array_ptr(&self) -> *const T { - match &self.inner { - Some(values) => values.as_ptr(), - None => std::ptr::null(), - } - } - - /// Returns a mutable pointer to the inner array. - #[inline(always)] - pub fn as_mut_array_ptr(&mut self) -> *mut T { - match &mut self.inner { - Some(values) => values.as_mut_ptr(), - None => std::ptr::null_mut(), - } - } -} - -impl LocalPointer>> { - /// Converts the inner vector of UTF-16 strings to a vector of `PWSTR`. - #[inline(always)] - pub fn as_pwstr_array(&self) -> Vec { - match &self.inner { - Some(values) => values - .iter() - .map(|value| windows::core::PWSTR(value.as_ptr() as _)) - .collect(), - None => vec![windows::core::PWSTR::null()], - } - } - - /// Converts the inner vector of UTF-16 strings to a vector of `PCWSTR`. - #[inline(always)] - pub fn as_pcwstr_array(&self) -> Vec { - match &self.inner { - Some(values) => values - .iter() - .map(|value| windows::core::PCWSTR::from_raw(value.as_ptr() as _)) - .collect(), - None => vec![windows::core::PCWSTR::null()], - } - } -} - -impl LocalPointer> { - /// Converts the inner UTF-16 string to a `PWSTR`. - #[inline(always)] - pub fn as_pwstr(&self) -> windows::core::PWSTR { - match &self.inner { - Some(value) => windows::core::PWSTR(value.as_ptr() as _), - None => windows::core::PWSTR::null(), - } - } - - /// Converts the inner UTF-16 string to a `PCWSTR`. - #[inline(always)] - pub fn as_pcwstr(&self) -> windows::core::PCWSTR { - match &self.inner { - Some(value) => windows::core::PCWSTR::from_raw(value.as_ptr() as _), - None => windows::core::PCWSTR::null(), - } - } -} diff --git a/opc_da/src/utils/mod.rs b/opc_da/src/utils/mod.rs deleted file mode 100644 index ce795b4..0000000 --- a/opc_da/src/utils/mod.rs +++ /dev/null @@ -1,7 +0,0 @@ -mod memory; -mod native; -mod try_iterator; - -pub use memory::*; -pub(crate) use native::*; -pub use try_iterator::*; diff --git a/opc_da/src/utils/native.rs b/opc_da/src/utils/native.rs deleted file mode 100644 index 47c5d17..0000000 --- a/opc_da/src/utils/native.rs +++ /dev/null @@ -1,164 +0,0 @@ -use super::{RemoteArray, RemotePointer}; - -pub(crate) trait IntoBridge { - fn into_bridge(self) -> Bridge; -} - -pub(crate) trait ToNative { - fn to_native(&self) -> Native; -} - -pub(crate) trait FromNative { - fn from_native(native: &Native) -> Self - where - Self: Sized; -} - -pub(crate) trait TryToNative { - fn try_to_native(&self) -> windows::core::Result; -} - -pub(crate) trait TryFromNative { - fn try_from_native(native: &Native) -> windows::core::Result - where - Self: Sized; -} - -pub(crate) trait TryToLocal { - fn try_to_local(&self) -> windows::core::Result; -} - -impl> TryToLocal for Native { - fn try_to_local(&self) -> windows::core::Result { - T::try_from_native(self) - } -} - -impl> TryFromNative for T { - fn try_from_native(native: &Native) -> windows::core::Result { - Ok(Self::from_native(native)) - } -} - -impl> TryToNative for T { - fn try_to_native(&self) -> windows::core::Result { - Ok(self.to_native()) - } -} - -impl> IntoBridge> for Vec { - fn into_bridge(self) -> Vec { - self.into_iter().map(IntoBridge::into_bridge).collect() - } -} - -impl + Clone> IntoBridge> for &[B] { - fn into_bridge(self) -> Vec { - self.iter().cloned().map(IntoBridge::into_bridge).collect() - } -} - -impl> TryToNative> for Vec { - fn try_to_native(&self) -> windows::core::Result> { - self.iter().map(TryToNative::try_to_native).collect() - } -} - -impl TryFromNative> for Vec> { - fn try_from_native( - native: &RemoteArray, - ) -> windows::core::Result { - Ok(native.as_slice().iter().map(|v| (*v).ok()).collect()) - } -} - -impl> TryFromNative> for Vec { - fn try_from_native(native: &RemoteArray) -> windows::core::Result { - native.as_slice().iter().map(T::try_from_native).collect() - } -} -impl> - TryFromNative<(RemoteArray, RemoteArray)> - for Vec> -{ - fn try_from_native( - native: &(RemoteArray, RemoteArray), - ) -> windows::core::Result { - let (results, errors) = native; - if results.len() != errors.len() { - return Err(windows::core::Error::new( - windows::Win32::Foundation::E_INVALIDARG, - "Results and errors arrays have different lengths", - )); - } - - Ok(results - .as_slice() - .iter() - .zip(errors.as_slice()) - .map(|(result, error)| { - if error.is_ok() { - T::try_from_native(result) - } else { - Err((*error).into()) - } - }) - .collect()) - } -} - -impl TryFromNative for std::time::SystemTime { - fn try_from_native( - native: &windows::Win32::Foundation::FILETIME, - ) -> windows::core::Result { - let ft = ((native.dwHighDateTime as u64) << 32) | (native.dwLowDateTime as u64); - let duration_since_1601 = std::time::Duration::from_nanos(ft * 100); - - let windows_to_unix_epoch_diff = std::time::Duration::from_secs(11_644_473_600); - let duration_since_unix_epoch = duration_since_1601 - .checked_sub(windows_to_unix_epoch_diff) - .ok_or_else(|| { - windows::core::Error::new( - windows::Win32::Foundation::E_INVALIDARG, - "FILETIME is before UNIX_EPOCH", - ) - })?; - - Ok(std::time::UNIX_EPOCH + duration_since_unix_epoch) - } -} - -#[macro_export] -macro_rules! try_from_native { - ($native:expr) => { - TryFromNative::try_from_native($native)? - }; -} - -impl TryToNative for std::time::SystemTime { - fn try_to_native(&self) -> windows::core::Result { - let duration_since_unix_epoch = - self.duration_since(std::time::UNIX_EPOCH).map_err(|_| { - windows::core::Error::new( - windows::Win32::Foundation::E_INVALIDARG, - "SystemTime is before UNIX_EPOCH", - ) - })?; - - let duration_since_windows_epoch = - duration_since_unix_epoch + std::time::Duration::from_secs(11_644_473_600); - - let ft = duration_since_windows_epoch.as_nanos() / 100; - - Ok(windows::Win32::Foundation::FILETIME { - dwLowDateTime: ft as u32, - dwHighDateTime: (ft >> 32) as u32, - }) - } -} - -impl TryFromNative for String { - fn try_from_native(native: &windows::core::PWSTR) -> windows::core::Result { - RemotePointer::from(*native).try_into() - } -} diff --git a/opc_da/src/utils/try_iterator.rs b/opc_da/src/utils/try_iterator.rs deleted file mode 100644 index cce11c0..0000000 --- a/opc_da/src/utils/try_iterator.rs +++ /dev/null @@ -1,98 +0,0 @@ -pub trait TryIterator { - type Item; - type Error; - - fn try_next(&mut self) -> Result, Self::Error>; -} - -pub struct TryIter { - inner: T, - done: bool, -} - -impl Iterator for TryIter { - type Item = Result; - - fn next(&mut self) -> Option { - if self.done { - return None; - } - - match self.inner.try_next() { - Ok(Some(item)) => Some(Ok(item)), - Ok(None) => { - self.done = true; - None - } - Err(e) => { - self.done = true; - Some(Err(e)) - } - } - } -} - -pub trait TryCacheIterator { - type Item; - type Error; - type Cache: IntoIterator; - - fn try_cache(&mut self) -> Result, Self::Error>; - - #[inline(always)] - fn into_iter(self) -> TryCacheIter - where - Self: Sized, - { - TryCacheIter::new(self) - } -} - -pub struct TryCacheIter { - inner: T, - cache: Option<<::Cache as std::iter::IntoIterator>::IntoIter>, - done: bool, -} - -impl TryCacheIter { - pub fn new(inner: T) -> Self { - Self { - inner, - cache: None, - done: false, - } - } -} - -impl Iterator for TryCacheIter { - type Item = Result; - - fn next(&mut self) -> Option { - if self.done { - return None; - } - - let next = match &mut self.cache { - Some(cache) => cache.next(), - None => None, - }; - - match next { - Some(item) => Some(Ok(item)), - None => match self.inner.try_cache() { - Ok(Some(cache)) => { - self.cache = Some(cache.into_iter()); - self.next() - } - Ok(None) => { - self.done = true; - None - } - Err(e) => { - self.done = true; - Some(Err(e)) - } - }, - } - } -} diff --git a/opc_da_bindings/Cargo.toml b/opc_da_bindings/Cargo.toml index 9859ed7..13b2d07 100644 --- a/opc_da_bindings/Cargo.toml +++ b/opc_da_bindings/Cargo.toml @@ -16,7 +16,6 @@ targets = [] [dependencies] windows = { workspace = true } windows-core = { workspace = true } -windows-targets = { workspace = true } [build-dependencies] windows-bindgen = { workspace = true } diff --git a/opc_da_bindings/build.rs b/opc_da_bindings/build.rs index 81fcc3c..7acb62f 100644 --- a/opc_da_bindings/build.rs +++ b/opc_da_bindings/build.rs @@ -13,7 +13,6 @@ fn main() { "--filter", "OPCDA", "--flat", - "--implement", ]) .unwrap(); } diff --git a/opc_hda_bindings/Cargo.toml b/opc_hda_bindings/Cargo.toml index 03330bf..9aabf75 100644 --- a/opc_hda_bindings/Cargo.toml +++ b/opc_hda_bindings/Cargo.toml @@ -16,7 +16,6 @@ targets = [] [dependencies] windows = { workspace = true } windows-core = { workspace = true } -windows-targets = { workspace = true } [build-dependencies] windows-bindgen = { workspace = true } diff --git a/opc_hda_bindings/build.rs b/opc_hda_bindings/build.rs index edfbc7d..97b203b 100644 --- a/opc_hda_bindings/build.rs +++ b/opc_hda_bindings/build.rs @@ -13,7 +13,6 @@ fn main() { "--filter", "OPCHDA", "--flat", - "--implement", ]) .unwrap(); }