From 5ecc5c6cb456bd11c96a69c7b5503e04d7f6a0d8 Mon Sep 17 00:00:00 2001 From: "w.pomp" Date: Mon, 22 Jun 2026 18:08:58 +0200 Subject: [PATCH] - Python: tree of python objects instead of tree of dicts - Rust: more derives --- .github/workflows/publish.yml | 171 - .github/workflows/publish_crates.yml | 66 + .github/workflows/publish_pypi.yml | 115 + .gitignore | 6 +- Cargo.toml | 38 +- LICENSE | 19 - README.md | 4 +- ome-metadata-derive/Cargo.toml | 11 + ome-metadata-derive/LICENSE-APACHE | 201 + ome-metadata-derive/LICENSE-MIT | 27 + ome-metadata-derive/README.md | 1 + ome-metadata-derive/src/lib.rs | 297 + ome-metadata/Cargo.toml | 32 + ome-metadata/LICENSE-APACHE | 201 + ome-metadata/LICENSE-MIT | 27 + ome-metadata/README.md | 25 + ome.xsd => ome-metadata/ome.xsd | 0 ome-metadata/pyproject.toml | 33 + {src => ome-metadata/src}/error.rs | 4 +- {src => ome-metadata/src}/lib.rs | 19 +- ome-metadata/src/ome.rs | 6035 +++++++++++++++++ ome-metadata/src/py.rs | 487 ++ .../tests}/1xp53-01-AP1.xml | 0 ...-CMV-1min-4h-01-Airyscan Processing-01.xml | 0 .../tests}/4-Pos_001_002.xml | 0 .../tests}/Experiment-2029.xml | 0 ...1-01-Airyscan Processing-01-Scene-2-P1.xml | 0 .../YTL1841B2-2-1_1hr_DMSO_galinduction_1.xml | 0 ...11_2023_05_04__14_46_19_cellnr_1_track.xml | 0 .../YTL1849A131_2023_05_04__13_36_36.xml | 0 .../tests}/YTL378_JF552.xml | 0 .../tests}/beads_2023_05_04__19_00_22.xml | 0 .../tests}/multi-channel.ome.xml | 0 {tests => ome-metadata/tests}/test.xml | 0 py/ome_metadata/__init__.py | 45 - pyproject.toml | 32 - src/ome.rs | 3022 --------- src/py.rs | 99 - 38 files changed, 7582 insertions(+), 3435 deletions(-) delete mode 100644 .github/workflows/publish.yml create mode 100644 .github/workflows/publish_crates.yml create mode 100644 .github/workflows/publish_pypi.yml delete mode 100644 LICENSE create mode 100644 ome-metadata-derive/Cargo.toml create mode 100644 ome-metadata-derive/LICENSE-APACHE create mode 100644 ome-metadata-derive/LICENSE-MIT create mode 100644 ome-metadata-derive/README.md create mode 100644 ome-metadata-derive/src/lib.rs create mode 100644 ome-metadata/Cargo.toml create mode 100644 ome-metadata/LICENSE-APACHE create mode 100644 ome-metadata/LICENSE-MIT create mode 100644 ome-metadata/README.md rename ome.xsd => ome-metadata/ome.xsd (100%) create mode 100644 ome-metadata/pyproject.toml rename {src => ome-metadata/src}/error.rs (74%) rename {src => ome-metadata/src}/lib.rs (77%) create mode 100644 ome-metadata/src/ome.rs create mode 100644 ome-metadata/src/py.rs rename {tests => ome-metadata/tests}/1xp53-01-AP1.xml (100%) rename {tests => ome-metadata/tests}/20230511-p53-4x-CMV-1min-4h-01-Airyscan Processing-01.xml (100%) rename {tests => ome-metadata/tests}/4-Pos_001_002.xml (100%) rename {tests => ome-metadata/tests}/Experiment-2029.xml (100%) rename {tests => ome-metadata/tests}/MK022_cE9_1-01-Airyscan Processing-01-Scene-2-P1.xml (100%) rename {tests => ome-metadata/tests}/YTL1841B2-2-1_1hr_DMSO_galinduction_1.xml (100%) rename {tests => ome-metadata/tests}/YTL1849A111_2023_05_04__14_46_19_cellnr_1_track.xml (100%) rename {tests => ome-metadata/tests}/YTL1849A131_2023_05_04__13_36_36.xml (100%) rename {tests => ome-metadata/tests}/YTL378_JF552.xml (100%) rename {tests => ome-metadata/tests}/beads_2023_05_04__19_00_22.xml (100%) rename {tests => ome-metadata/tests}/multi-channel.ome.xml (100%) rename {tests => ome-metadata/tests}/test.xml (100%) delete mode 100644 py/ome_metadata/__init__.py delete mode 100644 pyproject.toml delete mode 100644 src/ome.rs delete mode 100644 src/py.rs diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml deleted file mode 100644 index 1635963..0000000 --- a/.github/workflows/publish.yml +++ /dev/null @@ -1,171 +0,0 @@ -name: Publish - -on: [push, pull_request, workflow_call] - -permissions: - contents: read - -jobs: - linux: - runs-on: ${{ matrix.platform.runner }} - strategy: - matrix: - platform: - - runner: ubuntu-latest - target: x86_64 - - runner: ubuntu-latest - target: x86 - - runner: ubuntu-latest - target: aarch64 - - runner: ubuntu-latest - target: armv7 - - runner: ubuntu-latest - target: s390x - - runner: ubuntu-latest - target: ppc64le - steps: - - uses: actions/checkout@v6 - - uses: actions/setup-python@v6 - with: - python-version: '3.12' - - name: Build wheels - uses: PyO3/maturin-action@v1 - with: - target: ${{ matrix.platform.target }} - args: --release --out dist - sccache: 'true' - manylinux: auto - - name: Upload wheels - uses: actions/upload-artifact@v6 - with: - name: wheels-linux-${{ matrix.platform.target }} - path: dist - - windows: - runs-on: ${{ matrix.platform.runner }} - strategy: - matrix: - platform: - - runner: windows-latest - target: x64 -# - runner: windows-11-arm -# target: aarch64 - steps: - - uses: actions/checkout@v6 - - uses: actions/setup-python@v6 - with: - python-version: '3.12' - architecture: ${{ matrix.platform.target }} - - name: Build wheels - uses: PyO3/maturin-action@v1 - with: - target: ${{ matrix.platform.target }} - args: --release --out dist - sccache: 'true' - - name: Upload wheels - uses: actions/upload-artifact@v6 - with: - name: wheels-windows-${{ matrix.platform.target }} - path: dist - - macos: - runs-on: ${{ matrix.platform.runner }} - strategy: - matrix: - platform: - - runner: macos-latest - target: x86_64 - - runner: macos-14 - target: aarch64 - steps: - - uses: actions/checkout@v6 - - uses: actions/setup-python@v6 - with: - python-version: '3.12' - - name: Build wheels - uses: PyO3/maturin-action@v1 - with: - target: ${{ matrix.platform.target }} - args: --release --out dist - sccache: 'true' - - name: Upload wheels - uses: actions/upload-artifact@v6 - with: - name: wheels-macos-${{ matrix.platform.target }} - path: dist - - sdist: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v6 - - name: Build sdist - uses: PyO3/maturin-action@v1 - with: - command: sdist - args: --out dist - - name: Upload sdist - uses: actions/upload-artifact@v6 - with: - name: wheels-sdist - path: dist - - release: - name: Release - runs-on: ubuntu-latest - needs: [linux, windows, macos, sdist] - steps: - - uses: actions/download-artifact@v7 - - name: Publish to PyPI - uses: PyO3/maturin-action@v1 - env: - MATURIN_PYPI_TOKEN: ${{ secrets.PYPI_API_TOKEN }} - with: - command: upload - args: --non-interactive --skip-existing wheels-*/* - - crates_io_publish: - name: Publish (crates.io) - runs-on: ubuntu-latest - timeout-minutes: 25 - steps: - - uses: actions/checkout@v6 - - uses: dtolnay/rust-toolchain@stable - - - name: cargo-release Cache - id: cargo_release_cache - uses: actions/cache@v5 - with: - path: ~/.cargo/bin/cargo-release - key: ${{ runner.os }}-cargo-release - - - run: cargo install cargo-release - if: steps.cargo_release_cache.outputs.cache-hit != 'true' - - - name: cargo login - run: cargo login ${{ secrets.CRATES_IO_API_TOKEN }} - - # allow-branch HEAD is because GitHub actions switches - # to the tag while building, which is a detached head - - # Publishing is currently messy, because: - # - # * `peace_rt_model_core` exports `NativeError` or `WebError` depending on the target. - # * `peace_rt_model_web` fails to build when publishing the workspace for a native target. - # * `peace_rt_model_web` still needs its dependencies to be published before it can be - # published. - # * `peace_rt_model_hack` needs `peace_rt_model_web` to be published before it can be - # published. - # - # We *could* pass through `--no-verify` so `cargo` doesn't build the crate before publishing, - # which is reasonable, since this job only runs after the Linux, Windows, and WASM builds - # have passed. - - name: "cargo release publish" - run: |- - cargo release \ - publish \ - --workspace \ - --all-features \ - --allow-branch "main" \ - --no-confirm \ - --no-verify \ - --execute diff --git a/.github/workflows/publish_crates.yml b/.github/workflows/publish_crates.yml new file mode 100644 index 0000000..358acf4 --- /dev/null +++ b/.github/workflows/publish_crates.yml @@ -0,0 +1,66 @@ +name: Publish + +on: [workflow_dispatch] + +permissions: + contents: read + +jobs: + crates_io_publish: + name: Publish (crates.io) + runs-on: ubuntu-latest + timeout-minutes: 25 + steps: + - uses: actions/checkout@v6 + - name: Restore cache + uses: actions/cache/restore@v4 + with: + path: | + ~/.cargo + key: cache-ubuntu-cargo-publish + + - name: Install Rust + run: |- + export PATH="$HOME/.cargo/bin:$PATH" + if ! command -v rustc >/dev/null 2>&1; then + curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y + else + rustup update + fi + cargo install cargo-release + shell: bash + + # allow-branch HEAD is because GitHub actions switches + # to the tag while building, which is a detached head + + # Publishing is currently messy, because: + # + # * `peace_rt_model_core` exports `NativeError` or `WebError` depending on the target. + # * `peace_rt_model_web` fails to build when publishing the workspace for a native target. + # * `peace_rt_model_web` still needs its dependencies to be published before it can be + # published. + # * `peace_rt_model_hack` needs `peace_rt_model_web` to be published before it can be + # published. + # + # We *could* pass through `--no-verify` so `cargo` doesn't build the crate before publishing, + # which is reasonable, since this job only runs after the Linux, Windows, and WASM builds + # have passed. + - name: "cargo release publish" + run: |- + export PATH="$HOME/.osxcross/bin:$PATH" + cargo login ${{ secrets.CRATES_IO_API_TOKEN }} + cargo release \ + publish \ + --workspace \ + --all-features \ + --allow-branch "main" \ + --no-confirm \ + --no-verify \ + --execute + + - name: Store cache + uses: actions/cache/save@v4 + with: + path: | + ~/.cargo + key: cache-ubuntu-cargo-publish diff --git a/.github/workflows/publish_pypi.yml b/.github/workflows/publish_pypi.yml new file mode 100644 index 0000000..f8a8640 --- /dev/null +++ b/.github/workflows/publish_pypi.yml @@ -0,0 +1,115 @@ +name: CI + +on: [workflow_dispatch] + +permissions: + contents: read + +jobs: + pypi_publish: + name: Publish (pypi.org) + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v6 + - uses: actions/setup-python@v5 + with: + python-version: 3.x + + - name: Restore cache + uses: actions/cache/restore@v4 + with: + path: | + ~/.cache/pip + ~/.cache/pip-wheel + ~/.cache/sccache + ~/.cache/cargo-xwin + ~/.cargo + ~/.osxcross + key: cache-ubuntu-maturin-cross-compile + + - name: Install llvm + run: | + if ! command -v llvm-dlltool >/dev/null 2>&1; then + sudo apt update + sudo apt install -y llvm + fi + shell: bash + + - name: Install Rust + run: | + export PATH="$HOME/.cargo/bin:$PATH" + if ! command -v rustc >/dev/null 2>&1; then + curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y + else + rustup update + fi + shell: bash + + - name: Install sccache and maturin + run: | + export PATH="$HOME/.cargo/bin:$PATH" + python -m pip install --upgrade pip + pip install maturin ziglang + if ! command -v sccache >/dev/null 2>&1; then + cargo install sccache || pip install sccache + fi + shell: bash + + - name: Install xwin + run: | + export PATH="$HOME/.cargo/bin:$PATH" + if ! command -v cargo-xwin >/dev/null 2>&1; then + cargo install cargo-xwin || pip install cargo-xwin + cargo xwin cache xwin + fi + shell: bash + + - name: Install osxcross + run: | + export PATH="$HOME/.osxcross/bin:$PATH" + if ! command -v osxcross >/dev/null 2>&1; then + wget ${{ secrets.OSXCROSS_LINK }} -O osxcross.tar.gz + tar -xzf osxcross.tar.gz -C ~/ + mv ~/osxcross ~/.osxcross + fi + + - name: Build wheels + run: | + export PATH="$HOME/.cargo/bin:$HOME/.osxcross/bin:$PATH" + rm -rf dist + maturin sdist --out dist -m ome-metadata/Cargo.toml + rustup default nightly + + rustup target add x86_64-unknown-linux-gnu --toolchain nightly + maturin build --release --out ../dist --target x86_64-unknown-linux-gnu -m ome-metadata/Cargo.toml + rustup target add aarch64-unknown-linux-gnu --toolchain nightly + maturin build --release --out ../dist --target aarch64-unknown-linux-gnu --zig -m ome-metadata/Cargo.toml + + rustup target add x86_64-pc-windows-msvc --toolchain nightly + maturin build --release --out dist --target x86_64-pc-windows-msvc -m ome-metadata/Cargo.toml + rustup target add aarch64-pc-windows-msvc --toolchain nightly + maturin build --release --out dist --target aarch64-pc-windows-msvc -m ome-metadata/Cargo.toml + + rustup target add x86_64-apple-darwin --toolchain nightly + maturin build --release --out dist --target x86_64-apple-darwin --zig -m ome-metadata/Cargo.toml + rustup target add aarch64-apple-darwin --toolchain nightly + maturin build --release --out dist --target aarch64-apple-darwin --zig -m ome-metadata/Cargo.toml + + - name: Store cache + uses: actions/cache/save@v4 + with: + path: | + ~/.cache/pip + ~/.cache/pip-wheel + ~/.cache/sccache + ~/.cache/cargo-xwin + ~/.cargo + ~/.osxcross + key: cache-ubuntu-maturin-cross-compile + + - name: Publish to PyPI + uses: pypa/gh-action-pypi-publish@release/v1 + with: + password: ${{ secrets.PYPI_API_TOKEN }} + env: + GITHUB_WORKFLOW_REF: 1.10.1 diff --git a/.gitignore b/.gitignore index a878be3..843f2e3 100644 --- a/.gitignore +++ b/.gitignore @@ -70,5 +70,7 @@ docs/_build/ # Pyenv .python-version -/Cargo.lock -/tests/om/ +Cargo.lock +target/ + +.agentbridge diff --git a/Cargo.toml b/Cargo.toml index 2165e65..092e9e8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,34 +1,16 @@ -[package] -name = "ome-metadata" -version = "0.4.0" +[workspace] +resolver = "3" +members = ["ome-metadata", "ome-metadata-derive"] + +[workspace.package] +version = "0.5.0" edition = "2024" -rust-version = "1.85.1" +rust-version = "1.88.0" authors = ["Wim Pomp "] -license = "MIT" +license = "MIT OR Apache-2.0" description = "Ome metadata as a rust/python structure." -homepage = "https://github.com/wimpomp/ome-metadata" -repository = "https://github.com/wimpomp/ome-metadata" -documentation = "https://docs.rs/ome-metadata" +homepage = "https://git.pomppervova.nl/wim/ome-metadata" +repository = "https://git.pomppervova.nl/wim/ome-metadata" readme = "README.md" keywords = ["bioformats", "imread", "ome", "metadata"] categories = ["multimedia::images", "science"] -exclude = ["/tests"] - -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html -[lib] -name = "ome_metadata" -crate-type = ["cdylib", "rlib"] - -[dependencies] -enum-utils = "0.1" -serde = { version = "1", features = ["derive"] } -thiserror = "2" -quick-xml = { version = "0.38", features = ["serialize"] } - -[dependencies.pyo3] -version = "0.27" -features = ["extension-module", "abi3-py310", "generate-import-lib", "anyhow"] -optional = true - -[features] -python = ["dep:pyo3"] diff --git a/LICENSE b/LICENSE deleted file mode 100644 index f9b7904..0000000 --- a/LICENSE +++ /dev/null @@ -1,19 +0,0 @@ -Copyright (c) 2025 Wim Pomp - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. \ No newline at end of file diff --git a/README.md b/README.md index 3f11ec9..72cb636 100644 --- a/README.md +++ b/README.md @@ -9,7 +9,7 @@ use ome_metadata::Ome; let xml = read_to_string($file)?; let ome: Ome = xml.parse()?; -let image = &ome.image.unwrap()[0]; +let image = &ome.image[0]; println!("acquisition date: {:#?}", image.acquisition_date); ``` @@ -22,4 +22,4 @@ with open($file) as f: ome = Ome.from_xml(xml) image = ome.image[0] print(f"acquisition date: {image.acquisition_date}") -``` \ No newline at end of file +``` diff --git a/ome-metadata-derive/Cargo.toml b/ome-metadata-derive/Cargo.toml new file mode 100644 index 0000000..f7485c9 --- /dev/null +++ b/ome-metadata-derive/Cargo.toml @@ -0,0 +1,11 @@ +[package] +name = "ome-metadata-derive" +version = "0.5.0" +edition = "2024" + +[dependencies] +quote = "1" +syn = "2" + +[lib] +proc-macro = true \ No newline at end of file diff --git a/ome-metadata-derive/LICENSE-APACHE b/ome-metadata-derive/LICENSE-APACHE new file mode 100644 index 0000000..f8e5e5e --- /dev/null +++ b/ome-metadata-derive/LICENSE-APACHE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright [yyyy] [name of copyright owner] + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. \ No newline at end of file diff --git a/ome-metadata-derive/LICENSE-MIT b/ome-metadata-derive/LICENSE-MIT new file mode 100644 index 0000000..5a3aa7f --- /dev/null +++ b/ome-metadata-derive/LICENSE-MIT @@ -0,0 +1,27 @@ +Copyright (c) 2015 - 2021 Ulrik Sverdrup "bluss", + Jim Turner, + and ndarray developers + +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. \ No newline at end of file diff --git a/ome-metadata-derive/README.md b/ome-metadata-derive/README.md new file mode 100644 index 0000000..5d3092c --- /dev/null +++ b/ome-metadata-derive/README.md @@ -0,0 +1 @@ +# Derive macros for ome-metadata \ No newline at end of file diff --git a/ome-metadata-derive/src/lib.rs b/ome-metadata-derive/src/lib.rs new file mode 100644 index 0000000..bcdea0a --- /dev/null +++ b/ome-metadata-derive/src/lib.rs @@ -0,0 +1,297 @@ +use proc_macro::TokenStream; +use quote::quote; +use syn::{Data, DeriveInput, Fields, Visibility, parse_macro_input}; + +#[proc_macro_derive(OmeXML)] +pub fn ome_metadata_derive_xml(input: TokenStream) -> TokenStream { + let input = parse_macro_input!(input as DeriveInput); + let ident = input.ident; + + let expanded = quote! { + impl #ident { + pub fn from_xml>(s: T) -> Result { + Ok(from_str(s.as_ref())?) + } + + pub fn to_xml(&self) -> Result { + Ok(to_string(self)?) + } + } + }; + + TokenStream::from(expanded) +} + +#[proc_macro_derive(PyOmeComplexEnum)] +pub fn ome_metadata_derive_complex_enum(input: TokenStream) -> TokenStream { + let input = parse_macro_input!(input as DeriveInput); + let ident = input.ident; + + let mut variants = Vec::new(); + + match input.data { + Data::Enum(s) => { + for variant in &s.variants { + let variant_ident = &variant.ident; + variants.push(quote! { + Self::#variant_ident(v) => v.clone().into_bound_py_any(py)?, + }); + } + } + _ => { + return syn::Error::new_spanned(ident, "PyOmeComplexEnum only supports structs") + .to_compile_error() + .into(); + } + }; + + let expanded = quote! { + impl PyDisplay for #ident { + fn py_str(&self) -> String { + format!("{:?}", self) + } + } + + #[pyo3::prelude::pymethods] + impl #ident { + /// all possible variants of this enum that can be constructed or converted into + #[staticmethod] + fn variants() -> Vec { + Self::VARIANTS.iter().map(|v| v.trim_matches('"').to_string()).collect() + } + + fn __repr__(&self) -> String { + self.py_str() + } + + fn __str__(&self) -> String { + self.py_str() + } + + fn __getnewargs__<'py>(&self, py: Python<'py>) -> PyResult<(Bound<'py, PyAny>,)> { + Ok((match self { #(#variants)* },)) + } + + #[staticmethod] + #[pyo3(name = "from_xml")] + fn py_from_xml(xml: &str) -> PyResult { + Ok(Self::from_xml(xml)?) + } + + #[pyo3(name = "to_xml")] + fn py_to_xml(&self) -> PyResult { + Ok(self.to_xml()?) + } + } + }; + + TokenStream::from(expanded) +} + +#[proc_macro_derive(PyOmeEnum)] +pub fn ome_metadata_derive_enum(input: TokenStream) -> TokenStream { + let input = parse_macro_input!(input as DeriveInput); + let name = input.ident; + + let expanded = quote! { + impl PyDisplay for #name { + fn py_str(&self) -> String { + format!("{}", self) + } + } + + #[pyo3::prelude::pymethods] + impl #name { + #[new] + fn new(unit: &str) -> PyResult { + unit.parse().map_err(|_| PyErr::new::(format!("could not parse {}", unit))) + } + + /// all possible variants of this enum that can be constructed or converted into + #[staticmethod] + fn variants() -> Vec { + Self::VARIANTS.iter().map(|v| v.trim_matches('"').to_string()).collect() + } + + fn __repr__(&self) -> String { + self.py_str() + } + + fn __str__(&self) -> String { + self.py_str() + } + + fn __getnewargs__(&self) -> (String,) { + (format!("{}", self),) + } + + #[staticmethod] + #[pyo3(name = "from_xml")] + fn py_from_xml(xml: &str) -> PyResult { + Ok(Self::from_xml(xml)?) + } + + #[pyo3(name = "to_xml")] + fn py_to_xml(&self) -> PyResult { + Ok(self.to_xml()?) + } + } + }; + + TokenStream::from(expanded) +} + +#[proc_macro_derive(PyOmeUnit)] +pub fn ome_metadata_derive_unit(input: TokenStream) -> TokenStream { + let input = parse_macro_input!(input as DeriveInput); + let name = input.ident; + + let expanded = quote! { + impl PyDisplay for #name { + fn py_str(&self) -> String { + format!("{}", self) + } + } + + #[pyo3::prelude::pymethods] + impl #name { + #[new] + fn new(unit: &str) -> PyResult { + unit.parse().map_err(|_| PyErr::new::(format!("could not parse {}", unit))) + } + + /// convert a value between units + #[pyo3(name = "convert")] + fn py_convert(&self, unit: &Self, value: f64) -> PyResult { + Ok(self.convert(unit, value)?) + } + + /// all possible variants of this enum that can be constructed or converted into + #[staticmethod] + fn variants() -> Vec { + Self::VARIANTS.iter().map(|v| v.trim_matches('"').to_string()).collect() + } + + fn __repr__(&self) -> String { + self.py_str() + } + + fn __str__(&self) -> String { + self.py_str() + } + + fn __getnewargs__(&self) -> (String,) { + (format!("{}", self),) + } + + #[staticmethod] + #[pyo3(name = "from_xml")] + fn py_from_xml(xml: &str) -> PyResult { + Ok(Self::from_xml(xml)?) + } + + #[pyo3(name = "to_xml")] + fn py_to_xml(&self) -> PyResult { + Ok(self.to_xml()?) + } + } + }; + + TokenStream::from(expanded) +} + +#[proc_macro_derive(PyOme)] +pub fn ome_metadata_derive(input: TokenStream) -> TokenStream { + let input = parse_macro_input!(input as DeriveInput); + let name = input.ident; + + // Only support named structs + let fields = match input.data { + Data::Struct(s) => match s.fields { + Fields::Named(named) => named.named, + _ => { + return syn::Error::new_spanned(name, "PyOme only supports named structs") + .to_compile_error() + .into(); + } + }, + _ => { + return syn::Error::new_spanned(name, "PyOme only supports structs") + .to_compile_error() + .into(); + } + }; + + let mut idents = Vec::new(); + let mut types = Vec::new(); + let mut f = Vec::new(); + let mut ps = Vec::new(); + let mut new_kwargs = Vec::new(); + let mut s = Vec::new(); + + for field in fields.iter() { + let ty = &field.ty; + if let Some(ident) = &field.ident + && let Visibility::Public(_) = field.vis + { + let tmp = ident.to_string(); + let field_name = tmp.trim_start_matches("r#"); + idents.push(quote! { + self.#ident + }); + types.push(quote! { #ty }); + f.push(quote! { + pub #ident: #ty + }); + ps.push(quote! { + self.#ident.py_str() + }); + new_kwargs.push(quote! { + (#field_name, self.#ident.clone().into_bound_py_any(py)?) + }); + s.push(format!("{}: {{}}", field_name)); + } else { + return syn::Error::new_spanned(field, "PyOme type only supports public named fields") + .to_compile_error() + .into(); + } + } + let fmt = format!("{}({})", name, s.join(", ")); + + // Generate the token stream + let expanded = quote! { + impl PyDisplay for #name { + fn py_str(&self) -> String { + format!(#fmt, #(#ps,)*) + } + } + + #[pyo3::prelude::pymethods] + impl #name { + fn __getnewargs_ex__<'py>(&self, py: Python<'py>) -> PyResult<((), std::collections::HashMap<&str, Bound<'py, PyAny>>)> { + Ok(((), std::collections::HashMap::from_iter([#(#new_kwargs,)*]))) + } + + fn __repr__(&self) -> String { + self.py_str() + } + + fn __str__(&self) -> String { + self.py_str() + } + + #[staticmethod] + #[pyo3(name = "from_xml")] + fn py_from_xml(xml: &str) -> PyResult { + Ok(Self::from_xml(xml)?) + } + + #[pyo3(name = "to_xml")] + fn py_to_xml(&self) -> PyResult { + Ok(self.to_xml()?) + } + } + }; + + TokenStream::from(expanded) +} diff --git a/ome-metadata/Cargo.toml b/ome-metadata/Cargo.toml new file mode 100644 index 0000000..4c8b4db --- /dev/null +++ b/ome-metadata/Cargo.toml @@ -0,0 +1,32 @@ +[package] +name = "ome-metadata" +version = "0.5.0" +edition = "2024" +rust-version = "1.88.0" +authors = ["Wim Pomp "] +license = "MIT OR Apache-2.0" +description = "Ome metadata as a rust/python structure." +homepage = "https://git.pomppervova.nl/wim/ome-metadata" +repository = "https://git.pomppervova.nl/wim/ome-metadata" +documentation = "https://docs.rs/ome-metadata" +readme = "README.md" +keywords = ["bioformats", "imread", "ome", "metadata"] +categories = ["multimedia::images", "science"] +exclude = ["/tests"] + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html +[lib] +name = "ome_metadata" +crate-type = ["cdylib", "rlib"] + +[dependencies] +color-eyre = { version = "0.6", optional = true } +ome-metadata-derive = { path = "../ome-metadata-derive" } +pyo3 = { version = "0.29", features = ["abi3-py310", "anyhow", "eyre", "generate-import-lib"], optional = true} +quick-xml = { version = "0.40", features = ["serialize"] } +serde = { version = "1", features = ["derive"] } +strum = { version = "0.28", features = ["derive"] } +thiserror = "2" + +[features] +python = ["dep:pyo3", "dep:color-eyre"] diff --git a/ome-metadata/LICENSE-APACHE b/ome-metadata/LICENSE-APACHE new file mode 100644 index 0000000..f8e5e5e --- /dev/null +++ b/ome-metadata/LICENSE-APACHE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright [yyyy] [name of copyright owner] + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. \ No newline at end of file diff --git a/ome-metadata/LICENSE-MIT b/ome-metadata/LICENSE-MIT new file mode 100644 index 0000000..5a3aa7f --- /dev/null +++ b/ome-metadata/LICENSE-MIT @@ -0,0 +1,27 @@ +Copyright (c) 2015 - 2021 Ulrik Sverdrup "bluss", + Jim Turner, + and ndarray developers + +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. \ No newline at end of file diff --git a/ome-metadata/README.md b/ome-metadata/README.md new file mode 100644 index 0000000..11fdd59 --- /dev/null +++ b/ome-metadata/README.md @@ -0,0 +1,25 @@ +# ome-metadata + +Open Microscopy XML metadata (https://www.openmicroscopy.org/Schemas/) as a collection of Rust structs and enums, with translation to Python. + +## Rust +``` +use std::fs::read_to_string; +use ome_metadata::Ome; + +let xml = read_to_string($file)?; +let ome: Ome = xml.parse()?; +let image = &ome.image[0]; +println!("acquisition date: {:#?}", image.acquisition_date); +``` + +## Python +``` +from ome_metadata import Ome + +with open($file) as f: + xml = f.read() +ome = Ome.from_xml(xml) +image = ome.image[0] +print(f"acquisition date: {image.acquisition_date}") +``` \ No newline at end of file diff --git a/ome.xsd b/ome-metadata/ome.xsd similarity index 100% rename from ome.xsd rename to ome-metadata/ome.xsd diff --git a/ome-metadata/pyproject.toml b/ome-metadata/pyproject.toml new file mode 100644 index 0000000..4942246 --- /dev/null +++ b/ome-metadata/pyproject.toml @@ -0,0 +1,33 @@ +[build-system] +requires = ["maturin>=1.9.4,<2.0"] +build-backend = "maturin" + +[project] +name = "ome-metadata" +requires-python = ">=3.10" +classifiers = [ + "License :: OSI Approved :: MIT License", + "License :: OSI Approved :: Apache Software License", + "Programming Language :: Rust", + "Programming Language :: Python", + "Programming Language :: Python :: 3", +] +dynamic = [ + "version", + "description", + "readme", + "license", + "license-files", + "authors", + "maintainers", + "keywords", + "urls", +] + +[tool.maturin] +features = ["python"] +module-name = "ome_metadata" +strip = true + +[tool.isort] +line_length = 119 diff --git a/src/error.rs b/ome-metadata/src/error.rs similarity index 74% rename from src/error.rs rename to ome-metadata/src/error.rs index ff2e755..c86ec50 100644 --- a/src/error.rs +++ b/ome-metadata/src/error.rs @@ -5,7 +5,9 @@ pub enum Error { #[error(transparent)] IO(#[from] std::io::Error), #[error(transparent)] - SerdeXml(#[from] quick_xml::DeError), + XmlDe(#[from] quick_xml::DeError), + #[error(transparent)] + XmlSe(#[from] quick_xml::SeError), #[error("size of {0} is unknown")] SizeOfUnknown(String), #[error("no conversion to K by multiplication only")] diff --git a/src/lib.rs b/ome-metadata/src/lib.rs similarity index 77% rename from src/lib.rs rename to ome-metadata/src/lib.rs index 34ccd7f..d0d8925 100644 --- a/src/lib.rs +++ b/ome-metadata/src/lib.rs @@ -3,24 +3,14 @@ pub mod ome; pub mod error; #[cfg(feature = "python")] -mod py; +pub mod py; -use crate::error::Error; pub use ome::Ome; -use quick_xml::de::from_str; -use std::str::FromStr; - -impl FromStr for Ome { - type Err = Error; - - fn from_str(s: &str) -> Result { - Ok(from_str(s)?) - } -} #[cfg(test)] mod tests { - use super::*; + use crate::Ome; + use crate::error::Error; use std::fs::read_to_string; macro_rules! test_read { @@ -29,7 +19,8 @@ mod tests { #[test] fn $name() -> Result<(), Error> { let file = read_to_string(format!("tests/{}.xml", $file))?; - let _ome: Ome = file.parse()?; + let ome = Ome::from_xml(file)?; + let _xml = ome.to_xml()?; Ok(()) } )* diff --git a/ome-metadata/src/ome.rs b/ome-metadata/src/ome.rs new file mode 100644 index 0000000..c7fa8d7 --- /dev/null +++ b/ome-metadata/src/ome.rs @@ -0,0 +1,6035 @@ +#![allow(clippy::too_many_arguments)] +use crate::error::Error; +#[cfg(feature = "python")] +use crate::py::PyDisplay; +use ome_metadata_derive::OmeXML; +#[cfg(feature = "python")] +use ome_metadata_derive::{PyOme, PyOmeComplexEnum, PyOmeEnum, PyOmeUnit}; +#[cfg(feature = "python")] +use pyo3::IntoPyObjectExt; +#[cfg(feature = "python")] +use pyo3::prelude::*; +use quick_xml::de::from_str; +use quick_xml::se::to_string; +use serde::{Deserialize, Serialize}; +use std::cmp::PartialEq; +use strum::{AsRefStr, EnumString, VariantNames}; + +#[cfg_attr( + feature = "python", + pyclass( + module = "ome_metadata", + skip_from_py_object, + get_all, + set_all, + eq, + new = "from_fields" + ), + derive(FromPyObject, PyOme) +)] +#[derive(Clone, Debug, Serialize, Deserialize, Default, PartialEq, OmeXML)] +pub struct AffineTransform { + #[serde(rename = "@A00")] + pub a00: f32, + #[serde(rename = "@A10")] + pub a10: f32, + #[serde(rename = "@A01")] + pub a01: f32, + #[serde(rename = "@A11")] + pub a11: f32, + #[serde(rename = "@A02")] + pub a02: f32, + #[serde(rename = "@A12")] + pub a12: f32, +} +#[cfg_attr( + feature = "python", + pyclass( + module = "ome_metadata", + skip_from_py_object, + get_all, + set_all, + eq, + new = "from_fields" + ), + derive(FromPyObject, PyOme) +)] +#[derive(Clone, Debug, Serialize, Deserialize, Default, PartialEq, OmeXML)] +pub struct Annotation { + #[serde(rename = "@ID")] + pub id: String, + #[serde( + default, + rename = "@Namespace", + skip_serializing_if = "Option::is_none" + )] + pub namespace: Option, + #[serde( + default, + rename = "@Annotator", + skip_serializing_if = "Option::is_none" + )] + pub annotator: Option, + #[serde( + default, + rename = "Description", + skip_serializing_if = "Option::is_none" + )] + pub description: Option, + #[serde( + default, + rename = "AnnotationRef", + skip_serializing_if = "Vec::is_empty" + )] + pub annotation_ref: Vec, +} +#[cfg_attr( + feature = "python", + pyclass( + module = "ome_metadata", + skip_from_py_object, + get_all, + set_all, + eq, + new = "from_fields" + ), + derive(FromPyObject, PyOme) +)] +#[derive(Clone, Debug, Serialize, Deserialize, Default, Eq, PartialEq, OmeXML)] +pub struct AnnotationRef { + #[serde(rename = "@ID")] + pub id: String, +} +#[cfg_attr( + feature = "python", + pyclass( + module = "ome_metadata", + skip_from_py_object, + get_all, + set_all, + eq, + new = "from_fields" + ), + derive(FromPyObject, PyOme) +)] +#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, OmeXML)] +pub struct Arc { + #[serde( + default, + rename = "@Manufacturer", + skip_serializing_if = "Option::is_none" + )] + pub manufacturer: Option, + #[serde(default, rename = "@Model", skip_serializing_if = "Option::is_none")] + pub model: Option, + #[serde( + default, + rename = "@SerialNumber", + skip_serializing_if = "Option::is_none" + )] + pub serial_number: Option, + #[serde( + default, + rename = "@LotNumber", + skip_serializing_if = "Option::is_none" + )] + pub lot_number: Option, + #[serde(rename = "@ID")] + pub id: String, + #[serde(default, rename = "@Power", skip_serializing_if = "Option::is_none")] + pub power: Option, + #[serde(default = "Arc::default_power_unit", rename = "@PowerUnit")] + pub power_unit: UnitsPower, + #[serde(default, rename = "@Type", skip_serializing_if = "Option::is_none")] + pub r#type: Option, + #[serde( + default, + rename = "AnnotationRef", + skip_serializing_if = "Vec::is_empty" + )] + pub annotation_ref: Vec, +} +impl Arc { + pub fn default_power_unit() -> UnitsPower { + UnitsPower::W + } +} +impl Default for Arc { + fn default() -> Self { + Self { + manufacturer: None, + model: None, + serial_number: None, + lot_number: None, + id: String::new(), + power: None, + power_unit: Self::default_power_unit(), + r#type: None, + annotation_ref: Vec::new(), + } + } +} +#[derive( + EnumString, + AsRefStr, + Debug, + strum::Display, + Clone, + Copy, + PartialEq, + Eq, + PartialOrd, + Ord, + Hash, + Deserialize, + Serialize, + VariantNames, + OmeXML, +)] +#[strum(ascii_case_insensitive)] +#[cfg_attr( + feature = "python", + pyclass(module = "ome_metadata", from_py_object, get_all, set_all, eq), + derive(PyOmeEnum) +)] +pub enum ArcType { + #[serde(rename = "Hg")] + Hg, + #[serde(rename = "Xe")] + Xe, + #[serde(rename = "HgXe")] + HgXe, + #[serde(rename = "Other")] + Other, +} +#[cfg_attr( + feature = "python", + pyclass( + module = "ome_metadata", + skip_from_py_object, + get_all, + set_all, + eq, + new = "from_fields" + ), + derive(FromPyObject, PyOme) +)] +#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, OmeXML)] +pub struct BinData { + #[serde(default = "BinData::default_compression", rename = "@Compression")] + pub compression: BinDataCompressionType, + #[serde(rename = "@BigEndian")] + pub big_endian: bool, + #[serde(rename = "@Length")] + pub length: i64, + #[serde(rename = "$text")] + pub content: String, +} +impl BinData { + pub fn default_compression() -> BinDataCompressionType { + BinDataCompressionType::None + } +} +#[derive( + EnumString, + AsRefStr, + Debug, + strum::Display, + Clone, + Copy, + PartialEq, + Eq, + PartialOrd, + Ord, + Hash, + Deserialize, + Serialize, + VariantNames, + OmeXML, +)] +#[strum(ascii_case_insensitive)] +#[cfg_attr( + feature = "python", + pyclass(module = "ome_metadata", from_py_object, get_all, set_all, eq), + derive(PyOmeEnum) +)] +pub enum BinDataCompressionType { + #[serde(rename = "zlib")] + Zlib, + #[serde(rename = "bzip2")] + Bzip2, + #[serde(rename = "none")] + None, +} +#[cfg_attr( + feature = "python", + pyclass( + module = "ome_metadata", + skip_from_py_object, + get_all, + set_all, + eq, + new = "from_fields" + ), + derive(FromPyObject, PyOme) +)] +#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, OmeXML)] +pub struct BinaryFile { + #[serde(rename = "@FileName")] + pub file_name: String, + #[serde(rename = "@Size")] + pub size: i64, + #[serde(default, rename = "@MIMEType", skip_serializing_if = "Option::is_none")] + pub mime_type: Option, + #[serde(rename = "$value")] + pub content: BinaryFileContent, +} +#[derive( + AsRefStr, Debug, strum::Display, Clone, Deserialize, Serialize, VariantNames, PartialEq, OmeXML, +)] +#[strum(ascii_case_insensitive)] +#[cfg_attr( + feature = "python", + pyclass(module = "ome_metadata", from_py_object, get_all, set_all, eq), + derive(PyOmeComplexEnum) +)] +pub enum BinaryFileContent { + #[serde(rename = "External")] + External(External), + #[serde(rename = "BinData")] + BinData(BinData), +} +#[derive( + EnumString, + AsRefStr, + Debug, + strum::Display, + Clone, + Copy, + PartialEq, + Eq, + PartialOrd, + Ord, + Hash, + Deserialize, + Serialize, + VariantNames, + OmeXML, +)] +#[strum(ascii_case_insensitive)] +#[cfg_attr( + feature = "python", + pyclass(module = "ome_metadata", from_py_object, get_all, set_all, eq), + derive(PyOmeEnum) +)] +pub enum BinningType { + #[strum(serialize = "1x1")] + #[serde(rename = "1x1")] + _1X1, + #[strum(serialize = "2x2")] + #[serde(rename = "2x2")] + _2X2, + #[strum(serialize = "4x4")] + #[serde(rename = "4x4")] + _4X4, + #[strum(serialize = "8x8")] + #[serde(rename = "8x8")] + _8X8, + #[serde(rename = "Other")] + Other, +} +#[cfg_attr( + feature = "python", + pyclass( + module = "ome_metadata", + skip_from_py_object, + get_all, + set_all, + eq, + new = "from_fields" + ), + derive(FromPyObject, PyOme) +)] +#[derive(Clone, Debug, Serialize, Deserialize, Default, PartialEq, OmeXML)] +pub struct BooleanAnnotation { + #[serde(rename = "@ID")] + pub id: String, + #[serde( + default, + rename = "@Namespace", + skip_serializing_if = "Option::is_none" + )] + pub namespace: Option, + #[serde( + default, + rename = "@Annotator", + skip_serializing_if = "Option::is_none" + )] + pub annotator: Option, + #[serde( + default, + rename = "Description", + skip_serializing_if = "Option::is_none" + )] + pub description: Option, + #[serde( + default, + rename = "AnnotationRef", + skip_serializing_if = "Vec::is_empty" + )] + pub annotation_ref: Vec, + #[serde(rename = "Value")] + pub value: bool, +} +#[cfg_attr( + feature = "python", + pyclass( + module = "ome_metadata", + skip_from_py_object, + get_all, + set_all, + eq, + new = "from_fields" + ), + derive(FromPyObject, PyOme) +)] +#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, OmeXML)] +pub struct Channel { + #[serde(rename = "@ID")] + pub id: String, + #[serde(default, rename = "@Name", skip_serializing_if = "Option::is_none")] + pub name: Option, + #[serde( + default, + rename = "@SamplesPerPixel", + skip_serializing_if = "Option::is_none" + )] + pub samples_per_pixel: Option, + #[serde( + default, + rename = "@IlluminationType", + skip_serializing_if = "Option::is_none" + )] + pub illumination_type: Option, + #[serde( + default, + rename = "@PinholeSize", + skip_serializing_if = "Option::is_none" + )] + pub pinhole_size: Option, + #[serde( + default = "Channel::default_pinhole_size_unit", + rename = "@PinholeSizeUnit" + )] + pub pinhole_size_unit: UnitsLength, + #[serde( + default, + rename = "@AcquisitionMode", + skip_serializing_if = "Option::is_none" + )] + pub acquisition_mode: Option, + #[serde( + default, + rename = "@ContrastMethod", + skip_serializing_if = "Option::is_none" + )] + pub contrast_method: Option, + #[serde( + default, + rename = "@ExcitationWavelength", + skip_serializing_if = "Option::is_none" + )] + pub excitation_wavelength: Option, + #[serde( + default = "Channel::default_excitation_wavelength_unit", + rename = "@ExcitationWavelengthUnit" + )] + pub excitation_wavelength_unit: UnitsLength, + #[serde( + default, + rename = "@EmissionWavelength", + skip_serializing_if = "Option::is_none" + )] + pub emission_wavelength: Option, + #[serde( + default = "Channel::default_emission_wavelength_unit", + rename = "@EmissionWavelengthUnit" + )] + pub emission_wavelength_unit: UnitsLength, + #[serde(default, rename = "@Fluor", skip_serializing_if = "Option::is_none")] + pub fluor: Option, + #[serde(default, rename = "@NDFilter", skip_serializing_if = "Option::is_none")] + pub nd_filter: Option, + #[serde( + default, + rename = "@PockelCellSetting", + skip_serializing_if = "Option::is_none" + )] + pub pockel_cell_setting: Option, + #[serde(default = "Channel::default_color", rename = "@Color")] + pub color: i32, + #[serde( + default, + rename = "LightSourceSettings", + skip_serializing_if = "Option::is_none" + )] + pub light_source_settings: Option, + #[serde( + default, + rename = "DetectorSettings", + skip_serializing_if = "Option::is_none" + )] + pub detector_settings: Option, + #[serde( + default, + rename = "FilterSetRef", + skip_serializing_if = "Option::is_none" + )] + pub filter_set_ref: Option, + #[serde( + default, + rename = "AnnotationRef", + skip_serializing_if = "Vec::is_empty" + )] + pub annotation_ref: Vec, + #[serde(default, rename = "LightPath", skip_serializing_if = "Option::is_none")] + pub light_path: Option, +} +impl Channel { + pub fn default_pinhole_size_unit() -> UnitsLength { + UnitsLength::um + } + pub fn default_color() -> i32 { + 0 + } + pub fn default_excitation_wavelength_unit() -> UnitsLength { + UnitsLength::nm + } + pub fn default_emission_wavelength_unit() -> UnitsLength { + UnitsLength::nm + } +} +impl Default for Channel { + fn default() -> Self { + Self { + id: String::new(), + name: None, + samples_per_pixel: None, + illumination_type: None, + pinhole_size: None, + pinhole_size_unit: Self::default_pinhole_size_unit(), + acquisition_mode: None, + contrast_method: None, + excitation_wavelength: None, + excitation_wavelength_unit: Self::default_excitation_wavelength_unit(), + emission_wavelength: None, + emission_wavelength_unit: Self::default_emission_wavelength_unit(), + fluor: None, + nd_filter: None, + pockel_cell_setting: None, + color: Self::default_color(), + light_source_settings: None, + detector_settings: None, + filter_set_ref: None, + annotation_ref: Vec::new(), + light_path: None, + } + } +} +#[derive( + EnumString, + AsRefStr, + Debug, + strum::Display, + Clone, + Copy, + PartialEq, + Eq, + PartialOrd, + Ord, + Hash, + Deserialize, + Serialize, + VariantNames, + OmeXML, +)] +#[strum(ascii_case_insensitive)] +#[cfg_attr( + feature = "python", + pyclass(module = "ome_metadata", from_py_object, get_all, set_all, eq), + derive(PyOmeEnum) +)] +pub enum ChannelAcquisitionModeType { + #[serde(rename = "WideField")] + WideField, + #[serde(rename = "LaserScanningConfocalMicroscopy")] + LaserScanningConfocalMicroscopy, + #[serde(rename = "SpinningDiskConfocal")] + SpinningDiskConfocal, + #[serde(rename = "SlitScanConfocal")] + SlitScanConfocal, + #[serde(rename = "MultiPhotonMicroscopy")] + MultiPhotonMicroscopy, + #[serde(rename = "StructuredIllumination")] + StructuredIllumination, + #[serde(rename = "SingleMoleculeImaging")] + SingleMoleculeImaging, + #[serde(rename = "TotalInternalReflection")] + TotalInternalReflection, + #[serde(rename = "FluorescenceLifetime")] + FluorescenceLifetime, + #[serde(rename = "SpectralImaging")] + SpectralImaging, + #[serde(rename = "FluorescenceCorrelationSpectroscopy")] + FluorescenceCorrelationSpectroscopy, + #[serde(rename = "NearFieldScanningOpticalMicroscopy")] + NearFieldScanningOpticalMicroscopy, + #[serde(rename = "SecondHarmonicGenerationImaging")] + SecondHarmonicGenerationImaging, + #[serde(rename = "PALM")] + Palm, + #[serde(rename = "STORM")] + Storm, + #[serde(rename = "STED")] + Sted, + #[serde(rename = "TIRF")] + Tirf, + #[serde(rename = "FSM")] + Fsm, + #[serde(rename = "LCM")] + Lcm, + #[serde(rename = "Other")] + Other, + #[serde(rename = "BrightField")] + BrightField, + #[serde(rename = "SweptFieldConfocal")] + SweptFieldConfocal, + #[serde(rename = "SPIM")] + Spim, +} +#[derive( + EnumString, + AsRefStr, + Debug, + strum::Display, + Clone, + Copy, + PartialEq, + Eq, + PartialOrd, + Ord, + Hash, + Deserialize, + Serialize, + VariantNames, + OmeXML, +)] +#[strum(ascii_case_insensitive)] +#[cfg_attr( + feature = "python", + pyclass(module = "ome_metadata", from_py_object, get_all, set_all, eq), + derive(PyOmeEnum) +)] +pub enum ChannelContrastMethodType { + #[serde(rename = "Brightfield")] + Brightfield, + #[serde(rename = "Phase")] + Phase, + #[serde(rename = "DIC")] + Dic, + #[serde(rename = "HoffmanModulation")] + HoffmanModulation, + #[serde(rename = "ObliqueIllumination")] + ObliqueIllumination, + #[serde(rename = "PolarizedLight")] + PolarizedLight, + #[serde(rename = "Darkfield")] + Darkfield, + #[serde(rename = "Fluorescence")] + Fluorescence, + #[serde(rename = "Other")] + Other, +} +#[derive( + EnumString, + AsRefStr, + Debug, + strum::Display, + Clone, + Copy, + PartialEq, + Eq, + PartialOrd, + Ord, + Hash, + Deserialize, + Serialize, + VariantNames, + OmeXML, +)] +#[strum(ascii_case_insensitive)] +#[cfg_attr( + feature = "python", + pyclass(module = "ome_metadata", from_py_object, get_all, set_all, eq), + derive(PyOmeEnum) +)] +pub enum ChannelIlluminationType { + #[serde(rename = "Transmitted")] + Transmitted, + #[serde(rename = "Epifluorescence")] + Epifluorescence, + #[serde(rename = "Oblique")] + Oblique, + #[serde(rename = "NonLinear")] + NonLinear, + #[serde(rename = "Other")] + Other, +} +#[cfg_attr( + feature = "python", + pyclass( + module = "ome_metadata", + skip_from_py_object, + get_all, + set_all, + eq, + new = "from_fields" + ), + derive(FromPyObject, PyOme) +)] +#[derive(Clone, Debug, Serialize, Deserialize, Default, PartialEq, OmeXML)] +pub struct CommentAnnotation { + #[serde(rename = "@ID")] + pub id: String, + #[serde( + default, + rename = "@Namespace", + skip_serializing_if = "Option::is_none" + )] + pub namespace: Option, + #[serde( + default, + rename = "@Annotator", + skip_serializing_if = "Option::is_none" + )] + pub annotator: Option, + #[serde( + default, + rename = "Description", + skip_serializing_if = "Option::is_none" + )] + pub description: Option, + #[serde( + default, + rename = "AnnotationRef", + skip_serializing_if = "Vec::is_empty" + )] + pub annotation_ref: Vec, + #[serde(rename = "Value")] + pub value: String, +} +#[cfg_attr( + feature = "python", + pyclass( + module = "ome_metadata", + skip_from_py_object, + get_all, + set_all, + eq, + new = "from_fields" + ), + derive(FromPyObject, PyOme) +)] +#[derive(Clone, Debug, Serialize, Deserialize, Default, PartialEq, OmeXML)] +pub struct Dataset { + #[serde(default, rename = "@Name", skip_serializing_if = "Option::is_none")] + pub name: Option, + #[serde(rename = "@ID")] + pub id: String, + #[serde( + default, + rename = "Description", + skip_serializing_if = "Option::is_none" + )] + pub description: Option, + #[serde( + default, + rename = "ExperimenterRef", + skip_serializing_if = "Option::is_none" + )] + pub experimenter_ref: Option, + #[serde( + default, + rename = "ExperimenterGroupRef", + skip_serializing_if = "Option::is_none" + )] + pub experimenter_group_ref: Option, + #[serde(default, rename = "ImageRef", skip_serializing_if = "Vec::is_empty")] + pub image_ref: Vec, + #[serde( + default, + rename = "AnnotationRef", + skip_serializing_if = "Vec::is_empty" + )] + pub annotation_ref: Vec, +} +#[cfg_attr( + feature = "python", + pyclass( + module = "ome_metadata", + skip_from_py_object, + get_all, + set_all, + eq, + new = "from_fields" + ), + derive(FromPyObject, PyOme) +)] +#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, OmeXML)] +pub struct Detector { + #[serde( + default, + rename = "@Manufacturer", + skip_serializing_if = "Option::is_none" + )] + pub manufacturer: Option, + #[serde(default, rename = "@Model", skip_serializing_if = "Option::is_none")] + pub model: Option, + #[serde( + default, + rename = "@SerialNumber", + skip_serializing_if = "Option::is_none" + )] + pub serial_number: Option, + #[serde( + default, + rename = "@LotNumber", + skip_serializing_if = "Option::is_none" + )] + pub lot_number: Option, + #[serde(default, rename = "@Gain", skip_serializing_if = "Option::is_none")] + pub gain: Option, + #[serde(default, rename = "@Voltage", skip_serializing_if = "Option::is_none")] + pub voltage: Option, + #[serde(default = "Detector::default_voltage_unit", rename = "@VoltageUnit")] + pub voltage_unit: UnitsElectricPotential, + #[serde(default, rename = "@Offset", skip_serializing_if = "Option::is_none")] + pub offset: Option, + #[serde(default, rename = "@Zoom", skip_serializing_if = "Option::is_none")] + pub zoom: Option, + #[serde( + default, + rename = "@AmplificationGain", + skip_serializing_if = "Option::is_none" + )] + pub amplification_gain: Option, + #[serde(rename = "@ID")] + pub id: String, + #[serde(default, rename = "@Type", skip_serializing_if = "Option::is_none")] + pub r#type: Option, + #[serde( + default, + rename = "AnnotationRef", + skip_serializing_if = "Vec::is_empty" + )] + pub annotation_ref: Vec, +} +impl Detector { + pub fn default_voltage_unit() -> UnitsElectricPotential { + UnitsElectricPotential::V + } +} +impl Default for Detector { + fn default() -> Self { + Self { + manufacturer: None, + model: None, + serial_number: None, + lot_number: None, + gain: None, + voltage: None, + voltage_unit: Self::default_voltage_unit(), + offset: None, + zoom: None, + amplification_gain: None, + id: String::new(), + r#type: None, + annotation_ref: Vec::new(), + } + } +} +#[cfg_attr( + feature = "python", + pyclass( + module = "ome_metadata", + skip_from_py_object, + get_all, + set_all, + eq, + new = "from_fields" + ), + derive(FromPyObject, PyOme) +)] +#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, OmeXML)] +pub struct DetectorSettings { + #[serde(rename = "@ID")] + pub id: String, + #[serde(default, rename = "@Offset", skip_serializing_if = "Option::is_none")] + pub offset: Option, + #[serde(default, rename = "@Gain", skip_serializing_if = "Option::is_none")] + pub gain: Option, + #[serde(default, rename = "@Voltage", skip_serializing_if = "Option::is_none")] + pub voltage: Option, + #[serde( + default = "DetectorSettings::default_voltage_unit", + rename = "@VoltageUnit" + )] + pub voltage_unit: UnitsElectricPotential, + #[serde(default, rename = "@Zoom", skip_serializing_if = "Option::is_none")] + pub zoom: Option, + #[serde( + default, + rename = "@ReadOutRate", + skip_serializing_if = "Option::is_none" + )] + pub read_out_rate: Option, + #[serde( + default = "DetectorSettings::default_read_out_rate_unit", + rename = "@ReadOutRateUnit" + )] + pub read_out_rate_unit: UnitsFrequency, + #[serde(default, rename = "@Binning", skip_serializing_if = "Option::is_none")] + pub binning: Option, + #[serde( + default, + rename = "@Integration", + skip_serializing_if = "Option::is_none" + )] + pub integration: Option, +} +impl DetectorSettings { + pub fn default_voltage_unit() -> UnitsElectricPotential { + UnitsElectricPotential::V + } + pub fn default_read_out_rate_unit() -> UnitsFrequency { + UnitsFrequency::Hz + } +} +impl Default for DetectorSettings { + fn default() -> Self { + Self { + id: String::new(), + offset: None, + gain: None, + voltage: None, + voltage_unit: Self::default_voltage_unit(), + zoom: None, + read_out_rate: None, + read_out_rate_unit: Self::default_read_out_rate_unit(), + binning: None, + integration: None, + } + } +} +#[derive( + EnumString, + AsRefStr, + Debug, + strum::Display, + Clone, + Copy, + PartialEq, + Eq, + PartialOrd, + Ord, + Hash, + Deserialize, + Serialize, + VariantNames, + OmeXML, +)] +#[strum(ascii_case_insensitive)] +#[cfg_attr( + feature = "python", + pyclass(module = "ome_metadata", from_py_object, get_all, set_all, eq), + derive(PyOmeEnum) +)] +pub enum DetectorType { + #[serde(rename = "CCD")] + Ccd, + #[serde(rename = "IntensifiedCCD")] + IntensifiedCcd, + #[serde(rename = "AnalogVideo")] + AnalogVideo, + #[serde(rename = "PMT")] + Pmt, + #[serde(rename = "Photodiode")] + Photodiode, + #[serde(rename = "Spectroscopy")] + Spectroscopy, + #[serde(rename = "LifetimeImaging")] + LifetimeImaging, + #[serde(rename = "CorrelationSpectroscopy")] + CorrelationSpectroscopy, + #[serde(rename = "FTIR")] + Ftir, + #[serde(rename = "EMCCD")] + Emccd, + #[serde(rename = "APD")] + Apd, + #[serde(rename = "CMOS")] + Cmos, + #[serde(rename = "EBCCD")] + Ebccd, + #[serde(rename = "Other")] + Other, +} +#[cfg_attr( + feature = "python", + pyclass( + module = "ome_metadata", + skip_from_py_object, + get_all, + set_all, + eq, + new = "from_fields" + ), + derive(FromPyObject, PyOme) +)] +#[derive(Clone, Debug, Serialize, Deserialize, Default, PartialEq, OmeXML)] +pub struct Dichroic { + #[serde( + default, + rename = "@Manufacturer", + skip_serializing_if = "Option::is_none" + )] + pub manufacturer: Option, + #[serde(default, rename = "@Model", skip_serializing_if = "Option::is_none")] + pub model: Option, + #[serde( + default, + rename = "@SerialNumber", + skip_serializing_if = "Option::is_none" + )] + pub serial_number: Option, + #[serde( + default, + rename = "@LotNumber", + skip_serializing_if = "Option::is_none" + )] + pub lot_number: Option, + #[serde(rename = "@ID")] + pub id: String, + #[serde( + default, + rename = "AnnotationRef", + skip_serializing_if = "Vec::is_empty" + )] + pub annotation_ref: Vec, +} +#[cfg_attr( + feature = "python", + pyclass( + module = "ome_metadata", + skip_from_py_object, + get_all, + set_all, + eq, + new = "from_fields" + ), + derive(FromPyObject, PyOme) +)] +#[derive(Clone, Debug, Serialize, Deserialize, Default, PartialEq, OmeXML)] +pub struct DoubleAnnotation { + #[serde(rename = "@ID")] + pub id: String, + #[serde( + default, + rename = "@Namespace", + skip_serializing_if = "Option::is_none" + )] + pub namespace: Option, + #[serde( + default, + rename = "@Annotator", + skip_serializing_if = "Option::is_none" + )] + pub annotator: Option, + #[serde( + default, + rename = "Description", + skip_serializing_if = "Option::is_none" + )] + pub description: Option, + #[serde( + default, + rename = "AnnotationRef", + skip_serializing_if = "Vec::is_empty" + )] + pub annotation_ref: Vec, + #[serde(rename = "Value")] + pub value: f64, +} +#[cfg_attr( + feature = "python", + pyclass( + module = "ome_metadata", + skip_from_py_object, + get_all, + set_all, + eq, + new = "from_fields" + ), + derive(FromPyObject, PyOme) +)] +#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, OmeXML)] +pub struct Ellipse { + #[serde( + default, + rename = "@FillColor", + skip_serializing_if = "Option::is_none" + )] + pub fill_color: Option, + #[serde(default, rename = "@FillRule", skip_serializing_if = "Option::is_none")] + pub fill_rule: Option, + #[serde( + default, + rename = "@StrokeColor", + skip_serializing_if = "Option::is_none" + )] + pub stroke_color: Option, + #[serde( + default, + rename = "@StrokeWidth", + skip_serializing_if = "Option::is_none" + )] + pub stroke_width: Option, + #[serde( + default = "Ellipse::default_stroke_width_unit", + rename = "@StrokeWidthUnit" + )] + pub stroke_width_unit: UnitsLength, + #[serde( + default, + rename = "@StrokeDashArray", + skip_serializing_if = "Option::is_none" + )] + pub stroke_dash_array: Option, + #[serde(default, rename = "@Text", skip_serializing_if = "Option::is_none")] + pub text: Option, + #[serde( + default, + rename = "@FontFamily", + skip_serializing_if = "Option::is_none" + )] + pub font_family: Option, + #[serde(default, rename = "@FontSize", skip_serializing_if = "Option::is_none")] + pub font_size: Option, + #[serde(default = "Ellipse::default_font_size_unit", rename = "@FontSizeUnit")] + pub font_size_unit: UnitsLength, + #[serde( + default, + rename = "@FontStyle", + skip_serializing_if = "Option::is_none" + )] + pub font_style: Option, + #[serde(default, rename = "@Locked", skip_serializing_if = "Option::is_none")] + pub locked: Option, + #[serde(rename = "@ID")] + pub id: String, + #[serde(default, rename = "@TheZ", skip_serializing_if = "Option::is_none")] + pub the_z: Option, + #[serde(default, rename = "@TheT", skip_serializing_if = "Option::is_none")] + pub the_t: Option, + #[serde(default, rename = "@TheC", skip_serializing_if = "Option::is_none")] + pub the_c: Option, + #[serde(rename = "@X")] + pub x: f32, + #[serde(rename = "@Y")] + pub y: f32, + #[serde(rename = "@RadiusX")] + pub radius_x: f32, + #[serde(rename = "@RadiusY")] + pub radius_y: f32, + #[serde(default, rename = "Transform", skip_serializing_if = "Option::is_none")] + pub transform: Option, + #[serde( + default, + rename = "AnnotationRef", + skip_serializing_if = "Vec::is_empty" + )] + pub annotation_ref: Vec, +} +impl Ellipse { + pub fn default_stroke_width_unit() -> UnitsLength { + UnitsLength::Pixel + } + pub fn default_font_size_unit() -> UnitsLength { + UnitsLength::Pixel + } +} +impl Default for Ellipse { + fn default() -> Self { + Self { + fill_color: None, + fill_rule: None, + stroke_color: None, + stroke_width: None, + stroke_width_unit: Self::default_stroke_width_unit(), + stroke_dash_array: None, + text: None, + font_family: None, + font_size: None, + font_size_unit: Self::default_font_size_unit(), + font_style: None, + locked: None, + id: String::new(), + the_z: None, + the_t: None, + the_c: None, + x: 0.0, + y: 0.0, + radius_x: 0.0, + radius_y: 0.0, + transform: None, + annotation_ref: Vec::new(), + } + } +} +#[cfg_attr( + feature = "python", + pyclass( + module = "ome_metadata", + skip_from_py_object, + get_all, + set_all, + eq, + new = "from_fields" + ), + derive(FromPyObject, PyOme) +)] +#[derive(Clone, Debug, Serialize, Deserialize, Default, PartialEq, OmeXML)] +pub struct Experiment { + #[serde(default, rename = "@Type", skip_serializing_if = "Option::is_none")] + pub r#type: Option, + #[serde(rename = "@ID")] + pub id: String, + #[serde( + default, + rename = "Description", + skip_serializing_if = "Option::is_none" + )] + pub description: Option, + #[serde( + default, + rename = "ExperimenterRef", + skip_serializing_if = "Option::is_none" + )] + pub experimenter_ref: Option, + #[serde( + default, + rename = "MicrobeamManipulation", + skip_serializing_if = "Vec::is_empty" + )] + pub microbeam_manipulation: Vec, +} +#[derive( + EnumString, + AsRefStr, + Debug, + strum::Display, + Clone, + Copy, + PartialEq, + Eq, + PartialOrd, + Ord, + Hash, + Deserialize, + Serialize, + VariantNames, + OmeXML, +)] +#[strum(ascii_case_insensitive)] +#[cfg_attr( + feature = "python", + pyclass(module = "ome_metadata", from_py_object, get_all, set_all, eq), + derive(PyOmeEnum) +)] +pub enum ExperimentItemType { + #[serde(rename = "FP")] + Fp, + #[serde(rename = "FRET")] + Fret, + #[serde(rename = "TimeLapse")] + TimeLapse, + #[serde(rename = "FourDPlus")] + FourDPlus, + #[serde(rename = "Screen")] + Screen, + #[serde(rename = "Immunocytochemistry")] + Immunocytochemistry, + #[serde(rename = "Immunofluorescence")] + Immunofluorescence, + #[serde(rename = "FISH")] + Fish, + #[serde(rename = "Electrophysiology")] + Electrophysiology, + #[serde(rename = "IonImaging")] + IonImaging, + #[serde(rename = "Colocalization")] + Colocalization, + #[serde(rename = "PGIDocumentation")] + PgiDocumentation, + #[serde(rename = "FluorescenceLifetime")] + FluorescenceLifetime, + #[serde(rename = "SpectralImaging")] + SpectralImaging, + #[serde(rename = "Photobleaching")] + Photobleaching, + #[serde(rename = "SPIM")] + Spim, + #[serde(rename = "Other")] + Other, +} +#[cfg_attr( + feature = "python", + pyclass(module = "ome_metadata", skip_from_py_object, eq, new = "from_fields"), + derive(FromPyObject) +)] +#[derive(Clone, Debug, Serialize, Deserialize, Default, PartialEq, OmeXML)] +pub struct ExperimentType(pub Vec); +#[cfg_attr( + feature = "python", + pyclass( + module = "ome_metadata", + skip_from_py_object, + get_all, + set_all, + eq, + new = "from_fields" + ), + derive(FromPyObject, PyOme) +)] +#[derive(Clone, Debug, Serialize, Deserialize, Default, PartialEq, OmeXML)] +pub struct Experimenter { + #[serde(rename = "@ID")] + pub id: String, + #[serde( + default, + rename = "@FirstName", + skip_serializing_if = "Option::is_none" + )] + pub first_name: Option, + #[serde( + default, + rename = "@MiddleName", + skip_serializing_if = "Option::is_none" + )] + pub middle_name: Option, + #[serde(default, rename = "@LastName", skip_serializing_if = "Option::is_none")] + pub last_name: Option, + #[serde(default, rename = "@Email", skip_serializing_if = "Option::is_none")] + pub email: Option, + #[serde( + default, + rename = "@Institution", + skip_serializing_if = "Option::is_none" + )] + pub institution: Option, + #[serde(default, rename = "@UserName", skip_serializing_if = "Option::is_none")] + pub user_name: Option, + #[serde( + default, + rename = "AnnotationRef", + skip_serializing_if = "Vec::is_empty" + )] + pub annotation_ref: Vec, +} +#[cfg_attr( + feature = "python", + pyclass( + module = "ome_metadata", + skip_from_py_object, + get_all, + set_all, + eq, + new = "from_fields" + ), + derive(FromPyObject, PyOme) +)] +#[derive(Clone, Debug, Serialize, Deserialize, Default, PartialEq, OmeXML)] +pub struct ExperimenterGroup { + #[serde(default, rename = "@Name", skip_serializing_if = "Option::is_none")] + pub name: Option, + #[serde(rename = "@ID")] + pub id: String, + #[serde( + default, + rename = "Description", + skip_serializing_if = "Option::is_none" + )] + pub description: Option, + #[serde( + default, + rename = "ExperimenterRef", + skip_serializing_if = "Vec::is_empty" + )] + pub experimenter_ref: Vec, + #[serde(default, rename = "Leader", skip_serializing_if = "Vec::is_empty")] + pub leader: Vec, + #[serde( + default, + rename = "AnnotationRef", + skip_serializing_if = "Vec::is_empty" + )] + pub annotation_ref: Vec, +} +#[cfg_attr( + feature = "python", + pyclass( + module = "ome_metadata", + skip_from_py_object, + get_all, + set_all, + eq, + new = "from_fields" + ), + derive(FromPyObject, PyOme) +)] +#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, OmeXML)] +pub struct External { + #[serde(rename = "@href")] + pub href: String, + #[serde(rename = "@SHA1")] + pub sha_1: String, + #[serde(default = "External::default_compression", rename = "@Compression")] + pub compression: BinDataCompressionType, +} +impl External { + pub fn default_compression() -> BinDataCompressionType { + BinDataCompressionType::None + } +} +#[cfg_attr( + feature = "python", + pyclass( + module = "ome_metadata", + skip_from_py_object, + get_all, + set_all, + eq, + new = "from_fields" + ), + derive(FromPyObject, PyOme) +)] +#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, OmeXML)] +pub struct Filament { + #[serde( + default, + rename = "@Manufacturer", + skip_serializing_if = "Option::is_none" + )] + pub manufacturer: Option, + #[serde(default, rename = "@Model", skip_serializing_if = "Option::is_none")] + pub model: Option, + #[serde( + default, + rename = "@SerialNumber", + skip_serializing_if = "Option::is_none" + )] + pub serial_number: Option, + #[serde( + default, + rename = "@LotNumber", + skip_serializing_if = "Option::is_none" + )] + pub lot_number: Option, + #[serde(rename = "@ID")] + pub id: String, + #[serde(default, rename = "@Power", skip_serializing_if = "Option::is_none")] + pub power: Option, + #[serde(default = "Filament::default_power_unit", rename = "@PowerUnit")] + pub power_unit: UnitsPower, + #[serde(default, rename = "@Type", skip_serializing_if = "Option::is_none")] + pub r#type: Option, + #[serde( + default, + rename = "AnnotationRef", + skip_serializing_if = "Vec::is_empty" + )] + pub annotation_ref: Vec, +} +impl Filament { + pub fn default_power_unit() -> UnitsPower { + UnitsPower::W + } +} +impl Default for Filament { + fn default() -> Self { + Self { + manufacturer: None, + model: None, + serial_number: None, + lot_number: None, + id: String::new(), + power: None, + power_unit: Self::default_power_unit(), + r#type: None, + annotation_ref: Vec::new(), + } + } +} + +#[derive( + EnumString, + AsRefStr, + Debug, + strum::Display, + Clone, + Copy, + PartialEq, + Eq, + PartialOrd, + Ord, + Hash, + Deserialize, + Serialize, + VariantNames, + OmeXML, +)] +#[strum(ascii_case_insensitive)] +#[cfg_attr( + feature = "python", + pyclass(module = "ome_metadata", from_py_object, get_all, set_all, eq), + derive(PyOmeEnum) +)] +pub enum FilamentType { + #[serde(rename = "Incandescent")] + Incandescent, + #[serde(rename = "Halogen")] + Halogen, + #[serde(rename = "Other")] + Other, +} +#[cfg_attr( + feature = "python", + pyclass( + module = "ome_metadata", + skip_from_py_object, + get_all, + set_all, + eq, + new = "from_fields" + ), + derive(FromPyObject, PyOme) +)] +#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, OmeXML)] +pub struct FileAnnotation { + #[serde(rename = "@ID")] + pub id: String, + #[serde( + default, + rename = "@Namespace", + skip_serializing_if = "Option::is_none" + )] + pub namespace: Option, + #[serde( + default, + rename = "@Annotator", + skip_serializing_if = "Option::is_none" + )] + pub annotator: Option, + #[serde( + default, + rename = "Description", + skip_serializing_if = "Option::is_none" + )] + pub description: Option, + #[serde( + default, + rename = "AnnotationRef", + skip_serializing_if = "Vec::is_empty" + )] + pub annotation_ref: Vec, + #[serde(rename = "BinaryFile")] + pub binary_file: BinaryFile, +} +#[cfg_attr( + feature = "python", + pyclass( + module = "ome_metadata", + skip_from_py_object, + get_all, + set_all, + eq, + new = "from_fields" + ), + derive(FromPyObject, PyOme) +)] +#[derive(Clone, Debug, Serialize, Deserialize, Default, PartialEq, OmeXML)] +pub struct Filter { + #[serde( + default, + rename = "@Manufacturer", + skip_serializing_if = "Option::is_none" + )] + pub manufacturer: Option, + #[serde(default, rename = "@Model", skip_serializing_if = "Option::is_none")] + pub model: Option, + #[serde( + default, + rename = "@SerialNumber", + skip_serializing_if = "Option::is_none" + )] + pub serial_number: Option, + #[serde( + default, + rename = "@LotNumber", + skip_serializing_if = "Option::is_none" + )] + pub lot_number: Option, + #[serde(default, rename = "@Type", skip_serializing_if = "Option::is_none")] + pub r#type: Option, + #[serde( + default, + rename = "@FilterWheel", + skip_serializing_if = "Option::is_none" + )] + pub filter_wheel: Option, + #[serde(rename = "@ID")] + pub id: String, + #[serde( + default, + rename = "TransmittanceRange", + skip_serializing_if = "Option::is_none" + )] + pub transmittance_range: Option, + #[serde( + default, + rename = "AnnotationRef", + skip_serializing_if = "Vec::is_empty" + )] + pub annotation_ref: Vec, +} +#[cfg_attr( + feature = "python", + pyclass( + module = "ome_metadata", + skip_from_py_object, + get_all, + set_all, + eq, + new = "from_fields" + ), + derive(FromPyObject, PyOme) +)] +#[derive(Clone, Debug, Serialize, Deserialize, Default, PartialEq, OmeXML)] +pub struct FilterSet { + #[serde( + default, + rename = "@Manufacturer", + skip_serializing_if = "Option::is_none" + )] + pub manufacturer: Option, + #[serde(default, rename = "@Model", skip_serializing_if = "Option::is_none")] + pub model: Option, + #[serde( + default, + rename = "@SerialNumber", + skip_serializing_if = "Option::is_none" + )] + pub serial_number: Option, + #[serde( + default, + rename = "@LotNumber", + skip_serializing_if = "Option::is_none" + )] + pub lot_number: Option, + #[serde(rename = "@ID")] + pub id: String, + #[serde( + default, + rename = "ExcitationFilterRef", + skip_serializing_if = "Vec::is_empty" + )] + pub excitation_filter_ref: Vec, + #[serde( + default, + rename = "DichroicRef", + skip_serializing_if = "Option::is_none" + )] + pub dichroic_ref: Option, + #[serde( + default, + rename = "EmissionFilterRef", + skip_serializing_if = "Vec::is_empty" + )] + pub emission_filter_ref: Vec, +} +#[derive( + EnumString, + AsRefStr, + Debug, + strum::Display, + Clone, + Copy, + PartialEq, + Eq, + PartialOrd, + Ord, + Hash, + Deserialize, + Serialize, + VariantNames, + OmeXML, +)] +#[strum(ascii_case_insensitive)] +#[cfg_attr( + feature = "python", + pyclass(module = "ome_metadata", from_py_object, get_all, set_all, eq), + derive(PyOmeEnum) +)] +pub enum FilterType { + #[serde(rename = "Dichroic")] + Dichroic, + #[serde(rename = "LongPass")] + LongPass, + #[serde(rename = "ShortPass")] + ShortPass, + #[serde(rename = "BandPass")] + BandPass, + #[serde(rename = "MultiPass")] + MultiPass, + #[serde(rename = "NeutralDensity")] + NeutralDensity, + #[serde(rename = "Tuneable")] + Tuneable, + #[serde(rename = "Other")] + Other, +} +#[cfg_attr( + feature = "python", + pyclass( + module = "ome_metadata", + skip_from_py_object, + get_all, + set_all, + eq, + new = "from_fields" + ), + derive(FromPyObject, PyOme) +)] +#[derive(Clone, Debug, Serialize, Deserialize, Default, PartialEq, OmeXML)] +pub struct Folder { + #[serde(rename = "@ID")] + pub id: String, + #[serde(default, rename = "@Name", skip_serializing_if = "Option::is_none")] + pub name: Option, + #[serde( + default, + rename = "Description", + skip_serializing_if = "Option::is_none" + )] + pub description: Option, + #[serde(default, rename = "FolderRef", skip_serializing_if = "Vec::is_empty")] + pub folder_ref: Vec, + #[serde(default, rename = "ImageRef", skip_serializing_if = "Vec::is_empty")] + pub image_ref: Vec, + #[serde(default, rename = "ROIRef", skip_serializing_if = "Vec::is_empty")] + pub roi_ref: Vec, + #[serde( + default, + rename = "AnnotationRef", + skip_serializing_if = "Vec::is_empty" + )] + pub annotation_ref: Vec, +} +#[derive( + EnumString, + AsRefStr, + Debug, + strum::Display, + Clone, + Copy, + PartialEq, + Eq, + PartialOrd, + Ord, + Hash, + Deserialize, + Serialize, + VariantNames, + OmeXML, +)] +#[strum(ascii_case_insensitive)] +#[cfg_attr( + feature = "python", + pyclass(module = "ome_metadata", from_py_object, get_all, set_all, eq), + derive(PyOmeEnum) +)] +pub enum FontFamilyType { + #[serde(rename = "serif")] + Serif, + #[serde(rename = "sans-serif")] + SansSerif, + #[serde(rename = "cursive")] + Cursive, + #[serde(rename = "fantasy")] + Fantasy, + #[serde(rename = "monospace")] + Monospace, +} +#[cfg_attr( + feature = "python", + pyclass( + module = "ome_metadata", + skip_from_py_object, + get_all, + set_all, + eq, + new = "from_fields" + ), + derive(FromPyObject, PyOme) +)] +#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, OmeXML)] +pub struct GenericExcitationSource { + #[serde( + default, + rename = "@Manufacturer", + skip_serializing_if = "Option::is_none" + )] + pub manufacturer: Option, + #[serde(default, rename = "@Model", skip_serializing_if = "Option::is_none")] + pub model: Option, + #[serde( + default, + rename = "@SerialNumber", + skip_serializing_if = "Option::is_none" + )] + pub serial_number: Option, + #[serde( + default, + rename = "@LotNumber", + skip_serializing_if = "Option::is_none" + )] + pub lot_number: Option, + #[serde(rename = "@ID")] + pub id: String, + #[serde(default, rename = "@Power", skip_serializing_if = "Option::is_none")] + pub power: Option, + #[serde( + default = "GenericExcitationSource::default_power_unit", + rename = "@PowerUnit" + )] + pub power_unit: UnitsPower, + #[serde( + default, + rename = "AnnotationRef", + skip_serializing_if = "Vec::is_empty" + )] + pub annotation_ref: Vec, + #[serde(default, rename = "Map", skip_serializing_if = "Option::is_none")] + pub map: Option, +} +impl GenericExcitationSource { + pub fn default_power_unit() -> UnitsPower { + UnitsPower::W + } +} +impl Default for GenericExcitationSource { + fn default() -> Self { + Self { + manufacturer: None, + model: None, + serial_number: None, + lot_number: None, + id: String::new(), + power: None, + power_unit: Self::default_power_unit(), + annotation_ref: Vec::new(), + map: None, + } + } +} +#[cfg_attr( + feature = "python", + pyclass( + module = "ome_metadata", + skip_from_py_object, + get_all, + set_all, + eq, + new = "from_fields" + ), + derive(FromPyObject, PyOme) +)] +#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, OmeXML)] +pub struct Image { + #[serde(rename = "@ID")] + pub id: String, + #[serde(default, rename = "@Name", skip_serializing_if = "Option::is_none")] + pub name: Option, + #[serde( + default, + rename = "AcquisitionDate", + skip_serializing_if = "Option::is_none" + )] + pub acquisition_date: Option, + #[serde( + default, + rename = "ExperimenterRef", + skip_serializing_if = "Option::is_none" + )] + pub experimenter_ref: Option, + #[serde( + default, + rename = "Description", + skip_serializing_if = "Option::is_none" + )] + pub description: Option, + #[serde( + default, + rename = "ExperimentRef", + skip_serializing_if = "Option::is_none" + )] + pub experiment_ref: Option, + #[serde( + default, + rename = "ExperimenterGroupRef", + skip_serializing_if = "Option::is_none" + )] + pub experimenter_group_ref: Option, + #[serde( + default, + rename = "InstrumentRef", + skip_serializing_if = "Option::is_none" + )] + pub instrument_ref: Option, + #[serde( + default, + rename = "ObjectiveSettings", + skip_serializing_if = "Option::is_none" + )] + pub objective_settings: Option, + #[serde( + default, + rename = "ImagingEnvironment", + skip_serializing_if = "Option::is_none" + )] + pub imaging_environment: Option, + #[serde( + default, + rename = "StageLabel", + skip_serializing_if = "Option::is_none" + )] + pub stage_label: Option, + #[serde(rename = "Pixels")] + pub pixels: Pixels, + #[serde(default, rename = "ROIRef", skip_serializing_if = "Vec::is_empty")] + pub roi_ref: Vec, + #[serde( + default, + rename = "MicrobeamManipulationRef", + skip_serializing_if = "Vec::is_empty" + )] + pub microbeam_manipulation_ref: Vec, + #[serde( + default, + rename = "AnnotationRef", + skip_serializing_if = "Vec::is_empty" + )] + pub annotation_ref: Vec, +} +#[cfg_attr( + feature = "python", + pyclass( + module = "ome_metadata", + skip_from_py_object, + get_all, + set_all, + eq, + new = "from_fields" + ), + derive(FromPyObject, PyOme) +)] +#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, OmeXML)] +pub struct ImagingEnvironment { + #[serde( + default, + rename = "@Temperature", + skip_serializing_if = "Option::is_none" + )] + pub temperature: Option, + #[serde( + default = "ImagingEnvironment::default_temperature_unit", + rename = "@TemperatureUnit" + )] + pub temperature_unit: UnitsTemperature, + #[serde( + default, + rename = "@AirPressure", + skip_serializing_if = "Option::is_none" + )] + pub air_pressure: Option, + #[serde( + default = "ImagingEnvironment::default_air_pressure_unit", + rename = "@AirPressureUnit" + )] + pub air_pressure_unit: UnitsPressure, + #[serde(default, rename = "@Humidity", skip_serializing_if = "Option::is_none")] + pub humidity: Option, + #[serde( + default, + rename = "@CO2Percent", + skip_serializing_if = "Option::is_none" + )] + pub co_2_percent: Option, + #[serde(default, rename = "Map", skip_serializing_if = "Option::is_none")] + pub map: Option, +} +impl ImagingEnvironment { + pub fn default_temperature_unit() -> UnitsTemperature { + UnitsTemperature::C + } + pub fn default_air_pressure_unit() -> UnitsPressure { + UnitsPressure::atm + } +} +impl Default for ImagingEnvironment { + fn default() -> Self { + Self { + temperature: None, + temperature_unit: Self::default_temperature_unit(), + air_pressure: None, + air_pressure_unit: Self::default_air_pressure_unit(), + humidity: None, + co_2_percent: None, + map: None, + } + } +} +#[cfg_attr( + feature = "python", + pyclass( + module = "ome_metadata", + skip_from_py_object, + get_all, + set_all, + eq, + new = "from_fields" + ), + derive(FromPyObject, PyOme) +)] +#[derive(Clone, Debug, Serialize, Deserialize, Default, PartialEq, OmeXML)] +pub struct Instrument { + #[serde(rename = "@ID")] + pub id: String, + #[serde( + default, + rename = "Microscope", + skip_serializing_if = "Option::is_none" + )] + pub microscope: Option, + #[serde( + default, + rename = "LightSourceGroup", + skip_serializing_if = "Vec::is_empty" + )] + pub light_source_group: Vec, + #[serde(default, rename = "Detector", skip_serializing_if = "Vec::is_empty")] + pub detector: Vec, + #[serde(default, rename = "Objective", skip_serializing_if = "Vec::is_empty")] + pub objective: Vec, + #[serde(default, rename = "FilterSet", skip_serializing_if = "Vec::is_empty")] + pub filter_set: Vec, + #[serde(default, rename = "Filter", skip_serializing_if = "Vec::is_empty")] + pub filter: Vec, + #[serde(default, rename = "Dichroic", skip_serializing_if = "Vec::is_empty")] + pub dichroic: Vec, + #[serde( + default, + rename = "AnnotationRef", + skip_serializing_if = "Vec::is_empty" + )] + pub annotation_ref: Vec, +} +#[cfg_attr( + feature = "python", + pyclass( + module = "ome_metadata", + skip_from_py_object, + get_all, + set_all, + eq, + new = "from_fields" + ), + derive(FromPyObject, PyOme) +)] +#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, OmeXML)] +pub struct Label { + #[serde( + default, + rename = "@FillColor", + skip_serializing_if = "Option::is_none" + )] + pub fill_color: Option, + #[serde(default, rename = "@FillRule", skip_serializing_if = "Option::is_none")] + pub fill_rule: Option, + #[serde( + default, + rename = "@StrokeColor", + skip_serializing_if = "Option::is_none" + )] + pub stroke_color: Option, + #[serde( + default, + rename = "@StrokeWidth", + skip_serializing_if = "Option::is_none" + )] + pub stroke_width: Option, + #[serde( + default = "Label::default_stroke_width_unit", + rename = "@StrokeWidthUnit" + )] + pub stroke_width_unit: UnitsLength, + #[serde( + default, + rename = "@StrokeDashArray", + skip_serializing_if = "Option::is_none" + )] + pub stroke_dash_array: Option, + #[serde(default, rename = "@Text", skip_serializing_if = "Option::is_none")] + pub text: Option, + #[serde( + default, + rename = "@FontFamily", + skip_serializing_if = "Option::is_none" + )] + pub font_family: Option, + #[serde(default, rename = "@FontSize", skip_serializing_if = "Option::is_none")] + pub font_size: Option, + #[serde(default = "Label::default_font_size_unit", rename = "@FontSizeUnit")] + pub font_size_unit: UnitsLength, + #[serde( + default, + rename = "@FontStyle", + skip_serializing_if = "Option::is_none" + )] + pub font_style: Option, + #[serde(default, rename = "@Locked", skip_serializing_if = "Option::is_none")] + pub locked: Option, + #[serde(rename = "@ID")] + pub id: String, + #[serde(default, rename = "@TheZ", skip_serializing_if = "Option::is_none")] + pub the_z: Option, + #[serde(default, rename = "@TheT", skip_serializing_if = "Option::is_none")] + pub the_t: Option, + #[serde(default, rename = "@TheC", skip_serializing_if = "Option::is_none")] + pub the_c: Option, + #[serde(rename = "@X")] + pub x: f32, + #[serde(rename = "@Y")] + pub y: f32, + #[serde(default, rename = "Transform", skip_serializing_if = "Option::is_none")] + pub transform: Option, + #[serde( + default, + rename = "AnnotationRef", + skip_serializing_if = "Vec::is_empty" + )] + pub annotation_ref: Vec, +} +impl Label { + pub fn default_stroke_width_unit() -> UnitsLength { + UnitsLength::Pixel + } + pub fn default_font_size_unit() -> UnitsLength { + UnitsLength::Pixel + } +} +impl Default for Label { + fn default() -> Self { + Self { + fill_color: None, + fill_rule: None, + stroke_color: None, + stroke_width: None, + stroke_width_unit: Self::default_stroke_width_unit(), + stroke_dash_array: None, + text: None, + font_family: None, + font_size: None, + font_size_unit: Self::default_font_size_unit(), + font_style: None, + locked: None, + id: String::new(), + the_z: None, + the_t: None, + the_c: None, + x: 0.0, + y: 0.0, + transform: None, + annotation_ref: Vec::new(), + } + } +} +#[cfg_attr( + feature = "python", + pyclass( + module = "ome_metadata", + skip_from_py_object, + get_all, + set_all, + eq, + new = "from_fields" + ), + derive(FromPyObject, PyOme) +)] +#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, OmeXML)] +pub struct Laser { + #[serde( + default, + rename = "@Manufacturer", + skip_serializing_if = "Option::is_none" + )] + pub manufacturer: Option, + #[serde(default, rename = "@Model", skip_serializing_if = "Option::is_none")] + pub model: Option, + #[serde( + default, + rename = "@SerialNumber", + skip_serializing_if = "Option::is_none" + )] + pub serial_number: Option, + #[serde( + default, + rename = "@LotNumber", + skip_serializing_if = "Option::is_none" + )] + pub lot_number: Option, + #[serde(rename = "@ID")] + pub id: String, + #[serde(default, rename = "@Power", skip_serializing_if = "Option::is_none")] + pub power: Option, + #[serde(default = "Laser::default_power_unit", rename = "@PowerUnit")] + pub power_unit: UnitsPower, + #[serde(default, rename = "@Type", skip_serializing_if = "Option::is_none")] + pub r#type: Option, + #[serde( + default, + rename = "@LaserMedium", + skip_serializing_if = "Option::is_none" + )] + pub laser_medium: Option, + #[serde( + default, + rename = "@Wavelength", + skip_serializing_if = "Option::is_none" + )] + pub wavelength: Option, + #[serde(default = "Laser::default_wavelength_unit", rename = "@WavelengthUnit")] + pub wavelength_unit: UnitsLength, + #[serde( + default, + rename = "@FrequencyMultiplication", + skip_serializing_if = "Option::is_none" + )] + pub frequency_multiplication: Option, + #[serde(default, rename = "@Tuneable", skip_serializing_if = "Option::is_none")] + pub tuneable: Option, + #[serde(default, rename = "@Pulse", skip_serializing_if = "Option::is_none")] + pub pulse: Option, + #[serde( + default, + rename = "@PockelCell", + skip_serializing_if = "Option::is_none" + )] + pub pockel_cell: Option, + #[serde( + default, + rename = "@RepetitionRate", + skip_serializing_if = "Option::is_none" + )] + pub repetition_rate: Option, + #[serde( + default = "Laser::default_repetition_rate_unit", + rename = "@RepetitionRateUnit" + )] + pub repetition_rate_unit: UnitsFrequency, + #[serde( + default, + rename = "AnnotationRef", + skip_serializing_if = "Vec::is_empty" + )] + pub annotation_ref: Vec, + #[serde(default, rename = "Pump", skip_serializing_if = "Option::is_none")] + pub pump: Option, +} +impl Laser { + pub fn default_power_unit() -> UnitsPower { + UnitsPower::mW + } + pub fn default_wavelength_unit() -> UnitsLength { + UnitsLength::nm + } + pub fn default_repetition_rate_unit() -> UnitsFrequency { + UnitsFrequency::Hz + } +} +impl Default for Laser { + fn default() -> Self { + Self { + manufacturer: None, + model: None, + serial_number: None, + lot_number: None, + id: String::new(), + power: None, + power_unit: Self::default_power_unit(), + r#type: None, + laser_medium: None, + wavelength: None, + wavelength_unit: Self::default_wavelength_unit(), + frequency_multiplication: None, + tuneable: None, + pulse: None, + pockel_cell: None, + repetition_rate: None, + repetition_rate_unit: Self::default_repetition_rate_unit(), + annotation_ref: Vec::new(), + pump: None, + } + } +} +#[derive( + EnumString, + AsRefStr, + Debug, + strum::Display, + Clone, + Copy, + PartialEq, + Eq, + PartialOrd, + Ord, + Hash, + Deserialize, + Serialize, + VariantNames, + OmeXML, +)] +#[strum(ascii_case_insensitive)] +#[cfg_attr( + feature = "python", + pyclass(module = "ome_metadata", from_py_object, get_all, set_all, eq), + derive(PyOmeEnum) +)] +pub enum LaserLaserMediumType { + #[serde(rename = "Cu")] + Cu, + #[serde(rename = "Ag")] + Ag, + #[serde(rename = "ArFl")] + ArFl, + #[serde(rename = "ArCl")] + ArCl, + #[serde(rename = "KrFl")] + KrFl, + #[serde(rename = "KrCl")] + KrCl, + #[serde(rename = "XeFl")] + XeFl, + #[serde(rename = "XeCl")] + XeCl, + #[serde(rename = "XeBr")] + XeBr, + #[serde(rename = "N")] + N, + #[serde(rename = "Ar")] + Ar, + #[serde(rename = "Kr")] + Kr, + #[serde(rename = "Xe")] + Xe, + #[serde(rename = "HeNe")] + HeNe, + #[serde(rename = "HeCd")] + HeCd, + #[serde(rename = "CO")] + Co, + #[serde(rename = "CO2")] + Co2, + #[serde(rename = "H2O")] + H2O, + #[serde(rename = "HFl")] + Hfl, + #[serde(rename = "NdGlass")] + NdGlass, + #[serde(rename = "NdYAG")] + NdYag, + #[serde(rename = "ErGlass")] + ErGlass, + #[serde(rename = "ErYAG")] + ErYag, + #[serde(rename = "HoYLF")] + HoYlf, + #[serde(rename = "HoYAG")] + HoYag, + #[serde(rename = "Ruby")] + Ruby, + #[serde(rename = "TiSapphire")] + TiSapphire, + #[serde(rename = "Alexandrite")] + Alexandrite, + #[serde(rename = "Rhodamine6G")] + Rhodamine6G, + #[serde(rename = "CoumarinC30")] + CoumarinC30, + #[serde(rename = "GaAs")] + GaAs, + #[serde(rename = "GaAlAs")] + GaAlAs, + #[serde(rename = "EMinus")] + Eminus, + #[serde(rename = "Other")] + Other, +} +#[derive( + EnumString, + AsRefStr, + Debug, + strum::Display, + Clone, + Copy, + PartialEq, + Eq, + PartialOrd, + Ord, + Hash, + Deserialize, + Serialize, + VariantNames, + OmeXML, +)] +#[strum(ascii_case_insensitive)] +#[cfg_attr( + feature = "python", + pyclass(module = "ome_metadata", from_py_object, get_all, set_all, eq), + derive(PyOmeEnum) +)] +pub enum LaserPulseType { + #[serde(rename = "CW")] + Cw, + #[serde(rename = "Single")] + Single, + #[serde(rename = "QSwitched")] + Qswitched, + #[serde(rename = "Repetitive")] + Repetitive, + #[serde(rename = "ModeLocked")] + ModeLocked, + #[serde(rename = "Other")] + Other, +} +#[derive( + EnumString, + AsRefStr, + Debug, + strum::Display, + Clone, + Copy, + PartialEq, + Eq, + PartialOrd, + Ord, + Hash, + Deserialize, + Serialize, + VariantNames, + OmeXML, +)] +#[strum(ascii_case_insensitive)] +#[cfg_attr( + feature = "python", + pyclass(module = "ome_metadata", from_py_object, get_all, set_all, eq), + derive(PyOmeEnum) +)] +pub enum LaserType { + #[serde(rename = "Excimer")] + Excimer, + #[serde(rename = "Gas")] + Gas, + #[serde(rename = "MetalVapor")] + MetalVapor, + #[serde(rename = "SolidState")] + SolidState, + #[serde(rename = "Dye")] + Dye, + #[serde(rename = "Semiconductor")] + Semiconductor, + #[serde(rename = "FreeElectron")] + FreeElectron, + #[serde(rename = "Other")] + Other, +} +#[cfg_attr( + feature = "python", + pyclass( + module = "ome_metadata", + skip_from_py_object, + get_all, + set_all, + eq, + new = "from_fields" + ), + derive(FromPyObject, PyOme) +)] +#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, OmeXML)] +pub struct LightEmittingDiode { + #[serde( + default, + rename = "@Manufacturer", + skip_serializing_if = "Option::is_none" + )] + pub manufacturer: Option, + #[serde(default, rename = "@Model", skip_serializing_if = "Option::is_none")] + pub model: Option, + #[serde( + default, + rename = "@SerialNumber", + skip_serializing_if = "Option::is_none" + )] + pub serial_number: Option, + #[serde( + default, + rename = "@LotNumber", + skip_serializing_if = "Option::is_none" + )] + pub lot_number: Option, + #[serde(rename = "@ID")] + pub id: String, + #[serde(default, rename = "@Power", skip_serializing_if = "Option::is_none")] + pub power: Option, + #[serde( + default = "LightEmittingDiode::default_power_unit", + rename = "@PowerUnit" + )] + pub power_unit: UnitsPower, + #[serde( + default, + rename = "AnnotationRef", + skip_serializing_if = "Vec::is_empty" + )] + pub annotation_ref: Vec, +} +impl LightEmittingDiode { + pub fn default_power_unit() -> UnitsPower { + UnitsPower::mW + } +} +impl Default for LightEmittingDiode { + fn default() -> Self { + Self { + manufacturer: None, + model: None, + serial_number: None, + lot_number: None, + id: String::new(), + power: None, + power_unit: Self::default_power_unit(), + annotation_ref: Vec::new(), + } + } +} +#[cfg_attr( + feature = "python", + pyclass( + module = "ome_metadata", + skip_from_py_object, + get_all, + set_all, + eq, + new = "from_fields" + ), + derive(FromPyObject, PyOme) +)] +#[derive(Clone, Debug, Serialize, Deserialize, Default, PartialEq, OmeXML)] +pub struct LightPath { + #[serde( + default, + rename = "ExcitationFilterRef", + skip_serializing_if = "Vec::is_empty" + )] + pub excitation_filter_ref: Vec, + #[serde( + default, + rename = "DichroicRef", + skip_serializing_if = "Option::is_none" + )] + pub dichroic_ref: Option, + #[serde( + default, + rename = "EmissionFilterRef", + skip_serializing_if = "Vec::is_empty" + )] + pub emission_filter_ref: Vec, + #[serde( + default, + rename = "AnnotationRef", + skip_serializing_if = "Vec::is_empty" + )] + pub annotation_ref: Vec, +} +#[cfg_attr( + feature = "python", + pyclass( + module = "ome_metadata", + skip_from_py_object, + get_all, + set_all, + eq, + new = "from_fields" + ), + derive(FromPyObject, PyOme) +)] +#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, OmeXML)] +pub struct LightSourceType { + #[serde( + default, + rename = "@Manufacturer", + skip_serializing_if = "Option::is_none" + )] + pub manufacturer: Option, + #[serde(default, rename = "@Model", skip_serializing_if = "Option::is_none")] + pub model: Option, + #[serde( + default, + rename = "@SerialNumber", + skip_serializing_if = "Option::is_none" + )] + pub serial_number: Option, + #[serde( + default, + rename = "@LotNumber", + skip_serializing_if = "Option::is_none" + )] + pub lot_number: Option, + #[serde(rename = "@ID")] + pub id: String, + #[serde(default, rename = "@Power", skip_serializing_if = "Option::is_none")] + pub power: Option, + #[serde(default = "LightSourceType::default_power_unit", rename = "@PowerUnit")] + pub power_unit: UnitsPower, + #[serde( + default, + rename = "AnnotationRef", + skip_serializing_if = "Vec::is_empty" + )] + pub annotation_ref: Vec, +} +impl LightSourceType { + pub fn default_power_unit() -> UnitsPower { + UnitsPower::mW + } +} +impl Default for LightSourceType { + fn default() -> Self { + Self { + manufacturer: None, + model: None, + serial_number: None, + lot_number: None, + id: String::new(), + power: None, + power_unit: Self::default_power_unit(), + annotation_ref: Vec::new(), + } + } +} +#[derive( + EnumString, + AsRefStr, + Debug, + strum::Display, + Clone, + PartialEq, + Deserialize, + Serialize, + VariantNames, + OmeXML, +)] +#[strum(ascii_case_insensitive)] +#[cfg_attr( + feature = "python", + pyclass(module = "ome_metadata", from_py_object, get_all, set_all, eq), + derive(PyOmeComplexEnum) +)] +pub enum LightSourceGroup { + #[serde(rename = "Laser", alias = "Laser")] + Laser(Laser), + #[serde(rename = "Arc", alias = "Arc")] + Arc(Arc), + #[serde(rename = "Filament", alias = "Filament")] + Filament(Filament), + #[serde(rename = "LightEmittingDiode", alias = "LightEmittingDiode")] + LightEmittingDiode(LightEmittingDiode), + #[serde(rename = "GenericExcitationSource", alias = "GenericExcitationSource")] + GenericExcitationSource(GenericExcitationSource), +} +#[cfg_attr( + feature = "python", + pyclass( + module = "ome_metadata", + skip_from_py_object, + get_all, + set_all, + eq, + new = "from_fields" + ), + derive(FromPyObject, PyOme) +)] +#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, OmeXML)] +pub struct LightSourceSettings { + #[serde(rename = "@ID")] + pub id: String, + #[serde( + default, + rename = "@Attenuation", + skip_serializing_if = "Option::is_none" + )] + pub attenuation: Option, + #[serde( + default, + rename = "@Wavelength", + skip_serializing_if = "Option::is_none" + )] + pub wavelength: Option, + #[serde( + default = "LightSourceSettings::default_wavelength_unit", + rename = "@WavelengthUnit" + )] + pub wavelength_unit: UnitsLength, +} +impl LightSourceSettings { + pub fn default_wavelength_unit() -> UnitsLength { + UnitsLength::nm + } +} +impl Default for LightSourceSettings { + fn default() -> Self { + Self { + id: String::new(), + attenuation: None, + wavelength: None, + wavelength_unit: Self::default_wavelength_unit(), + } + } +} +#[cfg_attr( + feature = "python", + pyclass( + module = "ome_metadata", + skip_from_py_object, + get_all, + set_all, + eq, + new = "from_fields" + ), + derive(FromPyObject, PyOme) +)] +#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, OmeXML)] +pub struct Line { + #[serde( + default, + rename = "@FillColor", + skip_serializing_if = "Option::is_none" + )] + pub fill_color: Option, + #[serde(default, rename = "@FillRule", skip_serializing_if = "Option::is_none")] + pub fill_rule: Option, + #[serde( + default, + rename = "@StrokeColor", + skip_serializing_if = "Option::is_none" + )] + pub stroke_color: Option, + #[serde( + default, + rename = "@StrokeWidth", + skip_serializing_if = "Option::is_none" + )] + pub stroke_width: Option, + #[serde( + default = "Line::default_stroke_width_unit", + rename = "@StrokeWidthUnit" + )] + pub stroke_width_unit: UnitsLength, + #[serde( + default, + rename = "@StrokeDashArray", + skip_serializing_if = "Option::is_none" + )] + pub stroke_dash_array: Option, + #[serde(default, rename = "@Text", skip_serializing_if = "Option::is_none")] + pub text: Option, + #[serde( + default, + rename = "@FontFamily", + skip_serializing_if = "Option::is_none" + )] + pub font_family: Option, + #[serde(default, rename = "@FontSize", skip_serializing_if = "Option::is_none")] + pub font_size: Option, + #[serde(default = "Line::default_font_size_unit", rename = "@FontSizeUnit")] + pub font_size_unit: UnitsLength, + #[serde( + default, + rename = "@FontStyle", + skip_serializing_if = "Option::is_none" + )] + pub font_style: Option, + #[serde(default, rename = "@Locked", skip_serializing_if = "Option::is_none")] + pub locked: Option, + #[serde(rename = "@ID")] + pub id: String, + #[serde(default, rename = "@TheZ", skip_serializing_if = "Option::is_none")] + pub the_z: Option, + #[serde(default, rename = "@TheT", skip_serializing_if = "Option::is_none")] + pub the_t: Option, + #[serde(default, rename = "@TheC", skip_serializing_if = "Option::is_none")] + pub the_c: Option, + #[serde(rename = "@X1")] + pub x1: f32, + #[serde(rename = "@Y1")] + pub y1: f32, + #[serde(rename = "@X2")] + pub x2: f32, + #[serde(rename = "@Y2")] + pub y2: f32, + #[serde( + default, + rename = "@MarkerStart", + skip_serializing_if = "Option::is_none" + )] + pub marker_start: Option, + #[serde( + default, + rename = "@MarkerEnd", + skip_serializing_if = "Option::is_none" + )] + pub marker_end: Option, + #[serde(default, rename = "Transform", skip_serializing_if = "Option::is_none")] + pub transform: Option, + #[serde( + default, + rename = "AnnotationRef", + skip_serializing_if = "Vec::is_empty" + )] + pub annotation_ref: Vec, +} +impl Line { + pub fn default_stroke_width_unit() -> UnitsLength { + UnitsLength::Pixel + } + pub fn default_font_size_unit() -> UnitsLength { + UnitsLength::Pixel + } +} +impl Default for Line { + fn default() -> Self { + Self { + fill_color: None, + fill_rule: None, + stroke_color: None, + stroke_width: None, + stroke_width_unit: Self::default_stroke_width_unit(), + stroke_dash_array: None, + text: None, + font_family: None, + font_size: None, + font_size_unit: Self::default_font_size_unit(), + font_style: None, + locked: None, + id: String::new(), + the_z: None, + the_c: None, + the_t: None, + x1: 0.0, + y1: 0.0, + x2: 0.0, + y2: 0.0, + marker_start: None, + marker_end: None, + transform: None, + annotation_ref: Vec::new(), + } + } +} +#[cfg_attr( + feature = "python", + pyclass( + module = "ome_metadata", + skip_from_py_object, + get_all, + set_all, + eq, + new = "from_fields" + ), + derive(FromPyObject, PyOme) +)] +#[derive(Clone, Debug, Serialize, Deserialize, Default, PartialEq, OmeXML)] +pub struct LongAnnotation { + #[serde(rename = "@ID")] + pub id: String, + #[serde( + default, + rename = "@Namespace", + skip_serializing_if = "Option::is_none" + )] + pub namespace: Option, + #[serde( + default, + rename = "@Annotator", + skip_serializing_if = "Option::is_none" + )] + pub annotator: Option, + #[serde( + default, + rename = "Description", + skip_serializing_if = "Option::is_none" + )] + pub description: Option, + #[serde( + default, + rename = "AnnotationRef", + skip_serializing_if = "Vec::is_empty" + )] + pub annotation_ref: Vec, + #[serde(rename = "Value")] + pub value: i64, +} +#[cfg_attr( + feature = "python", + pyclass( + module = "ome_metadata", + skip_from_py_object, + get_all, + set_all, + eq, + new = "from_fields" + ), + derive(FromPyObject, PyOme) +)] +#[derive(Clone, Debug, Serialize, Deserialize, Default, PartialEq, OmeXML)] +pub struct MapType { + #[serde(default, rename = "M", skip_serializing_if = "Vec::is_empty")] + pub m: Vec, +} +#[cfg_attr( + feature = "python", + pyclass( + module = "ome_metadata", + skip_from_py_object, + get_all, + set_all, + eq, + new = "from_fields" + ), + derive(FromPyObject, PyOme) +)] +#[derive(Clone, Debug, Serialize, Deserialize, Default, PartialEq, OmeXML)] +pub struct MapAnnotation { + #[serde(rename = "@ID")] + pub id: String, + #[serde( + default, + rename = "@Namespace", + skip_serializing_if = "Option::is_none" + )] + pub namespace: Option, + #[serde( + default, + rename = "@Annotator", + skip_serializing_if = "Option::is_none" + )] + pub annotator: Option, + #[serde( + default, + rename = "Description", + skip_serializing_if = "Option::is_none" + )] + pub description: Option, + #[serde( + default, + rename = "AnnotationRef", + skip_serializing_if = "Vec::is_empty" + )] + pub annotation_ref: Vec, + #[serde(rename = "Value")] + pub value: MapType, +} +#[cfg_attr( + feature = "python", + pyclass( + module = "ome_metadata", + skip_from_py_object, + get_all, + set_all, + eq, + new = "from_fields" + ), + derive(FromPyObject, PyOme) +)] +#[derive(Clone, Debug, Serialize, Deserialize, Default, PartialEq, OmeXML)] +pub struct MapM { + #[serde(default, rename = "@K", skip_serializing_if = "Option::is_none")] + pub k: Option, + #[serde(rename = "$text")] + pub content: String, +} +#[derive( + EnumString, + AsRefStr, + Debug, + strum::Display, + Clone, + Copy, + PartialEq, + Eq, + PartialOrd, + Ord, + Hash, + Deserialize, + Serialize, + VariantNames, + OmeXML, +)] +#[strum(ascii_case_insensitive)] +#[cfg_attr( + feature = "python", + pyclass(module = "ome_metadata", from_py_object, get_all, set_all, eq), + derive(PyOmeEnum) +)] +pub enum MarkerType { + #[serde(rename = "Arrow")] + Arrow, +} +#[cfg_attr( + feature = "python", + pyclass( + module = "ome_metadata", + skip_from_py_object, + get_all, + set_all, + eq, + new = "from_fields" + ), + derive(FromPyObject, PyOme) +)] +#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, OmeXML)] +pub struct Mask { + #[serde( + default, + rename = "@FillColor", + skip_serializing_if = "Option::is_none" + )] + pub fill_color: Option, + #[serde(default, rename = "@FillRule", skip_serializing_if = "Option::is_none")] + pub fill_rule: Option, + #[serde( + default, + rename = "@StrokeColor", + skip_serializing_if = "Option::is_none" + )] + pub stroke_color: Option, + #[serde( + default, + rename = "@StrokeWidth", + skip_serializing_if = "Option::is_none" + )] + pub stroke_width: Option, + #[serde( + default = "Mask::default_stroke_width_unit", + rename = "@StrokeWidthUnit" + )] + pub stroke_width_unit: UnitsLength, + #[serde( + default, + rename = "@StrokeDashArray", + skip_serializing_if = "Option::is_none" + )] + pub stroke_dash_array: Option, + #[serde(default, rename = "@Text", skip_serializing_if = "Option::is_none")] + pub text: Option, + #[serde( + default, + rename = "@FontFamily", + skip_serializing_if = "Option::is_none" + )] + pub font_family: Option, + #[serde(default, rename = "@FontSize", skip_serializing_if = "Option::is_none")] + pub font_size: Option, + #[serde(default = "Mask::default_font_size_unit", rename = "@FontSizeUnit")] + pub font_size_unit: UnitsLength, + #[serde( + default, + rename = "@FontStyle", + skip_serializing_if = "Option::is_none" + )] + pub font_style: Option, + #[serde(default, rename = "@Locked", skip_serializing_if = "Option::is_none")] + pub locked: Option, + #[serde(rename = "@ID")] + pub id: String, + #[serde(default, rename = "@TheZ", skip_serializing_if = "Option::is_none")] + pub the_z: Option, + #[serde(default, rename = "@TheT", skip_serializing_if = "Option::is_none")] + pub the_t: Option, + #[serde(default, rename = "@TheC", skip_serializing_if = "Option::is_none")] + pub the_c: Option, + #[serde(rename = "@X")] + pub x: f32, + #[serde(rename = "@Y")] + pub y: f32, + #[serde(rename = "@Width")] + pub width: f32, + #[serde(rename = "@Height")] + pub height: f32, + #[serde(default, rename = "Transform", skip_serializing_if = "Option::is_none")] + pub transform: Option, + #[serde( + default, + rename = "AnnotationRef", + skip_serializing_if = "Vec::is_empty" + )] + pub annotation_ref: Vec, + #[serde(rename = "BinData")] + pub bin_data: BinData, +} +impl Mask { + pub fn default_stroke_width_unit() -> UnitsLength { + UnitsLength::Pixel + } + pub fn default_font_size_unit() -> UnitsLength { + UnitsLength::Pixel + } +} +#[cfg_attr( + feature = "python", + pyclass(module = "ome_metadata", skip_from_py_object, eq, new = "from_fields") +)] +#[derive(Clone, Debug, Serialize, Deserialize, Default, PartialEq, OmeXML)] +pub struct MetadataOnly; +#[cfg_attr( + feature = "python", + pyclass( + module = "ome_metadata", + skip_from_py_object, + get_all, + set_all, + eq, + new = "from_fields" + ), + derive(FromPyObject, PyOme) +)] +#[derive(Clone, Debug, Serialize, Deserialize, Default, PartialEq, OmeXML)] +pub struct MicrobeamManipulation { + #[serde(rename = "@ID")] + pub id: String, + #[serde(default, rename = "@Type", skip_serializing_if = "Option::is_none")] + pub r#type: Option, + #[serde( + default, + rename = "Description", + skip_serializing_if = "Option::is_none" + )] + pub description: Option, + #[serde(default, rename = "ROIRef", skip_serializing_if = "Vec::is_empty")] + pub roi_ref: Vec, + #[serde(rename = "ExperimenterRef")] + pub experimenter_ref: AnnotationRef, + #[serde( + default, + rename = "LightSourceSettings", + skip_serializing_if = "Vec::is_empty" + )] + pub light_source_settings: Vec, +} +#[derive( + EnumString, + AsRefStr, + Debug, + strum::Display, + Clone, + Copy, + PartialEq, + Eq, + PartialOrd, + Ord, + Hash, + Deserialize, + Serialize, + VariantNames, + OmeXML, +)] +#[strum(ascii_case_insensitive)] +#[cfg_attr( + feature = "python", + pyclass(module = "ome_metadata", from_py_object, get_all, set_all, eq), + derive(PyOmeEnum) +)] +pub enum MicrobeamManipulationItemType { + #[serde(rename = "FRAP")] + Frap, + #[serde(rename = "FLIP")] + Flip, + #[serde(rename = "InverseFRAP")] + InverseFrap, + #[serde(rename = "Photoablation")] + Photoablation, + #[serde(rename = "Photoactivation")] + Photoactivation, + #[serde(rename = "Uncaging")] + Uncaging, + #[serde(rename = "OpticalTrapping")] + OpticalTrapping, + #[serde(rename = "Other")] + Other, +} +#[cfg_attr( + feature = "python", + pyclass(module = "ome_metadata", skip_from_py_object, eq, new = "from_fields"), + derive(FromPyObject) +)] +#[derive(Clone, Debug, Serialize, Deserialize, Default, PartialEq, OmeXML)] +pub struct MicrobeamManipulationType(pub Vec); +#[cfg_attr( + feature = "python", + pyclass( + module = "ome_metadata", + skip_from_py_object, + get_all, + set_all, + eq, + new = "from_fields" + ), + derive(FromPyObject, PyOme) +)] +#[derive(Clone, Debug, Serialize, Deserialize, Default, PartialEq, OmeXML)] +pub struct Microscope { + #[serde( + default, + rename = "@Manufacturer", + skip_serializing_if = "Option::is_none" + )] + pub manufacturer: Option, + #[serde(default, rename = "@Model", skip_serializing_if = "Option::is_none")] + pub model: Option, + #[serde( + default, + rename = "@SerialNumber", + skip_serializing_if = "Option::is_none" + )] + pub serial_number: Option, + #[serde( + default, + rename = "@LotNumber", + skip_serializing_if = "Option::is_none" + )] + pub lot_number: Option, + #[serde(default, rename = "@Type", skip_serializing_if = "Option::is_none")] + pub r#type: Option, +} +#[derive( + EnumString, + AsRefStr, + Debug, + strum::Display, + Clone, + Copy, + PartialEq, + Eq, + PartialOrd, + Ord, + Hash, + Deserialize, + Serialize, + VariantNames, + OmeXML, +)] +#[strum(ascii_case_insensitive)] +#[cfg_attr( + feature = "python", + pyclass(module = "ome_metadata", from_py_object, get_all, set_all, eq), + derive(PyOmeEnum) +)] +pub enum MicroscopeType { + #[serde(rename = "Upright")] + Upright, + #[serde(rename = "Inverted")] + Inverted, + #[serde(rename = "Dissection")] + Dissection, + #[serde(rename = "Electrophysiology")] + Electrophysiology, + #[serde(rename = "Other")] + Other, +} +#[derive( + EnumString, + AsRefStr, + Debug, + strum::Display, + Clone, + Copy, + PartialEq, + Eq, + PartialOrd, + Ord, + Hash, + Deserialize, + Serialize, + VariantNames, + OmeXML, +)] +#[strum(ascii_case_insensitive)] +#[cfg_attr( + feature = "python", + pyclass(module = "ome_metadata", from_py_object, get_all, set_all, eq), + derive(PyOmeEnum) +)] +pub enum NamingConventionType { + #[serde(rename = "letter")] + Letter, + #[serde(rename = "number")] + Number, +} + +/// The root of the metadata, create this by parsing an XML string. +/// ``` +/// use ome_metadata::Ome; +/// +/// let xml = r#" +/// +/// 2025-01-29T14:42:42 +/// +/// +/// +/// +/// +/// +/// +/// +/// "#; +/// +/// let ome = Ome::from_xml(xml).unwrap(); +/// let image = &ome.image[0]; +/// println!("acquisition date: {:#?}", image.acquisition_date); +/// ``` + +#[derive(Clone, Debug, Serialize, Deserialize, Default, PartialEq)] +#[cfg_attr( + feature = "python", + pyclass( + module = "ome_metadata", + skip_from_py_object, + get_all, + set_all, + eq, + new = "from_fields" + ), + derive(FromPyObject, PyOme) +)] +pub struct Ome { + #[serde(default, rename = "@UUID", skip_serializing_if = "Option::is_none")] + pub uuid: Option, + #[serde(default, rename = "@Creator", skip_serializing_if = "Option::is_none")] + pub creator: Option, + #[serde(rename = "Rights", skip_serializing_if = "Option::is_none")] + pub rights: Option, + #[serde(default, rename = "Project", skip_serializing_if = "Vec::is_empty")] + pub project: Vec, + #[serde(default, rename = "Dataset", skip_serializing_if = "Vec::is_empty")] + pub dataset: Vec, + #[serde(default, rename = "Folder", skip_serializing_if = "Vec::is_empty")] + pub folder: Vec, + #[serde(default, rename = "Experiment", skip_serializing_if = "Vec::is_empty")] + pub experiment: Vec, + #[serde(default, rename = "Plate", skip_serializing_if = "Vec::is_empty")] + pub plate: Vec, + #[serde(default, rename = "Screen", skip_serializing_if = "Vec::is_empty")] + pub screen: Vec, + #[serde( + default, + rename = "Experimenter", + skip_serializing_if = "Vec::is_empty" + )] + pub experimenter: Vec, + #[serde( + default, + rename = "ExperimenterGroup", + skip_serializing_if = "Vec::is_empty" + )] + pub experimenter_group: Vec, + #[serde(default, rename = "Instrument", skip_serializing_if = "Vec::is_empty")] + pub instrument: Vec, + #[serde(default, rename = "Image", skip_serializing_if = "Vec::is_empty")] + pub image: Vec, + #[serde( + rename = "StructuredAnnotations", + skip_serializing_if = "Option::is_none" + )] + pub structured_annotations: Option, + #[serde(default, rename = "ROI", skip_serializing_if = "Vec::is_empty")] + pub roi: Vec, + #[serde(rename = "BinaryOnly", skip_serializing_if = "Option::is_none")] + pub binary_only: Option, +} +impl Ome { + pub fn from_xml>(s: T) -> Result { + Ok(from_str(s.as_ref())?) + } + + pub fn to_xml(&self) -> Result { + Ok(to_string(self)?.replace("", r###""###).replace("", "")) + } +} +#[cfg_attr( + feature = "python", + pyclass( + module = "ome_metadata", + skip_from_py_object, + get_all, + set_all, + eq, + new = "from_fields" + ), + derive(FromPyObject, PyOme) +)] +#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, OmeXML)] +pub struct Objective { + #[serde( + default, + rename = "@Manufacturer", + skip_serializing_if = "Option::is_none" + )] + pub manufacturer: Option, + #[serde(default, rename = "@Model", skip_serializing_if = "Option::is_none")] + pub model: Option, + #[serde( + default, + rename = "@SerialNumber", + skip_serializing_if = "Option::is_none" + )] + pub serial_number: Option, + #[serde( + default, + rename = "@LotNumber", + skip_serializing_if = "Option::is_none" + )] + pub lot_number: Option, + #[serde(rename = "@ID")] + pub id: String, + #[serde( + default, + rename = "@Correction", + skip_serializing_if = "Option::is_none" + )] + pub correction: Option, + #[serde( + default, + rename = "@Immersion", + skip_serializing_if = "Option::is_none" + )] + pub immersion: Option, + #[serde(default, rename = "@LensNA", skip_serializing_if = "Option::is_none")] + pub lens_na: Option, + #[serde( + default, + rename = "@NominalMagnification", + skip_serializing_if = "Option::is_none" + )] + pub nominal_magnification: Option, + #[serde( + default, + rename = "@CalibratedMagnification", + skip_serializing_if = "Option::is_none" + )] + pub calibrated_magnification: Option, + #[serde( + default, + rename = "@WorkingDistance", + skip_serializing_if = "Option::is_none" + )] + pub working_distance: Option, + #[serde( + default = "Objective::default_working_distance_unit", + rename = "@WorkingDistanceUnit" + )] + pub working_distance_unit: UnitsLength, + #[serde(default, rename = "@Iris", skip_serializing_if = "Option::is_none")] + pub iris: Option, + #[serde( + default, + rename = "AnnotationRef", + skip_serializing_if = "Vec::is_empty" + )] + pub annotation_ref: Vec, +} +impl Objective { + pub fn default_working_distance_unit() -> UnitsLength { + UnitsLength::um + } +} +impl Default for Objective { + fn default() -> Self { + Self { + manufacturer: None, + model: None, + serial_number: None, + lot_number: None, + id: String::new(), + correction: None, + immersion: None, + lens_na: None, + nominal_magnification: None, + calibrated_magnification: None, + working_distance: None, + working_distance_unit: Self::default_working_distance_unit(), + iris: None, + annotation_ref: Vec::new(), + } + } +} +#[derive( + EnumString, + AsRefStr, + Debug, + strum::Display, + Clone, + Copy, + PartialEq, + Eq, + PartialOrd, + Ord, + Hash, + Deserialize, + Serialize, + VariantNames, + OmeXML, +)] +#[strum(ascii_case_insensitive)] +#[cfg_attr( + feature = "python", + pyclass(module = "ome_metadata", from_py_object, get_all, set_all, eq), + derive(PyOmeEnum) +)] +pub enum ObjectiveCorrectionType { + #[serde(rename = "UV")] + Uv, + #[serde(rename = "PlanApo")] + PlanApo, + #[serde(rename = "PlanFluor")] + PlanFluor, + #[serde(rename = "SuperFluor")] + SuperFluor, + #[serde(rename = "VioletCorrected")] + VioletCorrected, + #[serde(rename = "Achro")] + Achro, + #[serde(rename = "Achromat")] + Achromat, + #[serde(rename = "Fluor")] + Fluor, + #[serde(rename = "Fl")] + Fl, + #[serde(rename = "Fluar")] + Fluar, + #[serde(rename = "Neofluar")] + Neofluar, + #[serde(rename = "Fluotar")] + Fluotar, + #[serde(rename = "Apo")] + Apo, + #[serde(rename = "PlanNeofluar")] + PlanNeofluar, + #[serde(rename = "Other")] + Other, +} +#[derive( + EnumString, + AsRefStr, + Debug, + strum::Display, + Clone, + Copy, + PartialEq, + Eq, + PartialOrd, + Ord, + Hash, + Deserialize, + Serialize, + VariantNames, + OmeXML, +)] +#[strum(ascii_case_insensitive)] +#[cfg_attr( + feature = "python", + pyclass(module = "ome_metadata", from_py_object, get_all, set_all, eq), + derive(PyOmeEnum) +)] +pub enum ObjectiveImmersionType { + #[serde(rename = "Oil")] + Oil, + #[serde(rename = "Water")] + Water, + #[serde(rename = "WaterDipping")] + WaterDipping, + #[serde(rename = "Air")] + Air, + #[serde(rename = "Multi")] + Multi, + #[serde(rename = "Glycerol")] + Glycerol, + #[serde(rename = "Other")] + Other, +} +#[cfg_attr( + feature = "python", + pyclass( + module = "ome_metadata", + skip_from_py_object, + get_all, + set_all, + eq, + new = "from_fields" + ), + derive(FromPyObject, PyOme) +)] +#[derive(Clone, Debug, Serialize, Deserialize, Default, PartialEq, OmeXML)] +pub struct ObjectiveSettings { + #[serde(rename = "@ID")] + pub id: String, + #[serde( + default, + rename = "@CorrectionCollar", + skip_serializing_if = "Option::is_none" + )] + pub correction_collar: Option, + #[serde(default, rename = "@Medium", skip_serializing_if = "Option::is_none")] + pub medium: Option, + #[serde( + default, + rename = "@RefractiveIndex", + skip_serializing_if = "Option::is_none" + )] + pub refractive_index: Option, +} +#[derive( + EnumString, + AsRefStr, + Debug, + strum::Display, + Clone, + Copy, + PartialEq, + Eq, + PartialOrd, + Ord, + Hash, + Deserialize, + Serialize, + VariantNames, + OmeXML, +)] +#[strum(ascii_case_insensitive)] +#[cfg_attr( + feature = "python", + pyclass(module = "ome_metadata", from_py_object, get_all, set_all, eq), + derive(PyOmeEnum) +)] +pub enum ObjectiveSettingsMediumType { + #[serde(rename = "Air")] + Air, + #[serde(rename = "Oil")] + Oil, + #[serde(rename = "Water")] + Water, + #[serde(rename = "Glycerol")] + Glycerol, + #[serde(rename = "Other")] + Other, +} +#[cfg_attr( + feature = "python", + pyclass( + module = "ome_metadata", + skip_from_py_object, + get_all, + set_all, + eq, + new = "from_fields" + ), + derive(FromPyObject, PyOme) +)] +#[derive(Clone, Debug, Serialize, Deserialize, Default, PartialEq, OmeXML)] +pub struct OmeBinaryOnly { + #[serde(rename = "@MetadataFile")] + pub metadata_file: String, + #[serde(rename = "@UUID")] + pub uuid: String, +} +#[derive( + EnumString, + AsRefStr, + Debug, + strum::Display, + Clone, + Copy, + PartialEq, + Eq, + PartialOrd, + Ord, + Hash, + Deserialize, + Serialize, + VariantNames, + OmeXML, +)] +#[strum(ascii_case_insensitive)] +#[cfg_attr( + feature = "python", + pyclass(module = "ome_metadata", from_py_object, get_all, set_all, eq), + derive(PyOmeEnum) +)] +pub enum PixelType { + #[serde(rename = "int8")] + Int8, + #[serde(rename = "int16")] + Int16, + #[serde(rename = "int32")] + Int32, + #[serde(rename = "uint8")] + Uint8, + #[serde(rename = "uint16")] + Uint16, + #[serde(rename = "uint32")] + Uint32, + #[serde(rename = "float")] + Float, + #[serde(rename = "double")] + Double, + #[serde(rename = "complex")] + Complex, + #[serde(rename = "double-complex")] + DoubleComplex, + #[serde(rename = "bit")] + Bit, +} +#[cfg_attr( + feature = "python", + pyclass( + module = "ome_metadata", + skip_from_py_object, + get_all, + set_all, + eq, + new = "from_fields" + ), + derive(FromPyObject, PyOme) +)] +#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, OmeXML)] +pub struct Pixels { + #[serde(rename = "@ID")] + pub id: String, + #[serde(rename = "@DimensionOrder")] + pub dimension_order: PixelsDimensionOrderType, + #[serde(rename = "@Type")] + pub r#type: PixelType, + #[serde( + default, + rename = "@SignificantBits", + skip_serializing_if = "Option::is_none" + )] + pub significant_bits: Option, + #[serde( + default, + rename = "@Interleaved", + skip_serializing_if = "Option::is_none" + )] + pub interleaved: Option, + #[serde( + default, + rename = "@BigEndian", + skip_serializing_if = "Option::is_none" + )] + pub big_endian: Option, + #[serde(rename = "@SizeX")] + pub size_x: i32, + #[serde(rename = "@SizeY")] + pub size_y: i32, + #[serde(rename = "@SizeZ")] + pub size_z: i32, + #[serde(rename = "@SizeC")] + pub size_c: i32, + #[serde(rename = "@SizeT")] + pub size_t: i32, + #[serde( + default, + rename = "@PhysicalSizeX", + skip_serializing_if = "Option::is_none" + )] + pub physical_size_x: Option, + #[serde( + default = "Pixels::default_physical_size_x_unit", + rename = "@PhysicalSizeXUnit" + )] + pub physical_size_x_unit: UnitsLength, + #[serde( + default, + rename = "@PhysicalSizeY", + skip_serializing_if = "Option::is_none" + )] + pub physical_size_y: Option, + #[serde( + default = "Pixels::default_physical_size_y_unit", + rename = "@PhysicalSizeYUnit" + )] + pub physical_size_y_unit: UnitsLength, + #[serde( + default, + rename = "@PhysicalSizeZ", + skip_serializing_if = "Option::is_none" + )] + pub physical_size_z: Option, + #[serde( + default = "Pixels::default_physical_size_z_unit", + rename = "@PhysicalSizeZUnit" + )] + pub physical_size_z_unit: UnitsLength, + #[serde( + default, + rename = "@TimeIncrement", + skip_serializing_if = "Option::is_none" + )] + pub time_increment: Option, + #[serde( + default = "Pixels::default_time_increment_unit", + rename = "@TimeIncrementUnit" + )] + pub time_increment_unit: UnitsTime, + #[serde(default, rename = "Channel", skip_serializing_if = "Vec::is_empty")] + pub channel: Vec, + #[serde(default, rename = "BinData", skip_serializing_if = "Vec::is_empty")] + pub bin_data: Vec, + #[serde(default, rename = "TiffData", skip_serializing_if = "Vec::is_empty")] + pub tiff_data: Vec, + #[serde(rename = "MetadataOnly", skip_serializing_if = "Option::is_none")] + pub metadata_only: Option, + #[serde(default, rename = "Plane", skip_serializing_if = "Vec::is_empty")] + pub plane: Vec, +} +impl Pixels { + pub fn default_physical_size_x_unit() -> UnitsLength { + UnitsLength::um + } + pub fn default_physical_size_y_unit() -> UnitsLength { + UnitsLength::um + } + pub fn default_physical_size_z_unit() -> UnitsLength { + UnitsLength::um + } + pub fn default_time_increment_unit() -> UnitsTime { + UnitsTime::s + } +} +#[derive( + EnumString, + AsRefStr, + Debug, + strum::Display, + Clone, + Copy, + PartialEq, + Eq, + PartialOrd, + Ord, + Hash, + Deserialize, + Serialize, + VariantNames, + OmeXML, +)] +#[strum(ascii_case_insensitive)] +#[cfg_attr( + feature = "python", + pyclass(module = "ome_metadata", from_py_object, get_all, set_all, eq), + derive(PyOmeEnum) +)] +pub enum PixelsDimensionOrderType { + #[serde(rename = "XYZCT")] + Xyzct, + #[serde(rename = "XYZTC")] + Xyztc, + #[serde(rename = "XYCTZ")] + Xyctz, + #[serde(rename = "XYCZT")] + Xyczt, + #[serde(rename = "XYTCZ")] + Xytcz, + #[serde(rename = "XYTZC")] + Xytzc, +} +#[cfg_attr( + feature = "python", + pyclass( + module = "ome_metadata", + skip_from_py_object, + get_all, + set_all, + eq, + new = "from_fields" + ), + derive(FromPyObject, PyOme) +)] +#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, OmeXML)] +pub struct Plane { + #[serde(rename = "@TheZ")] + pub the_z: Option, + #[serde(rename = "@TheT")] + pub the_t: Option, + #[serde(rename = "@TheC")] + pub the_c: Option, + #[serde(default, rename = "@DeltaT", skip_serializing_if = "Option::is_none")] + pub delta_t: Option, + #[serde(default = "Plane::default_delta_t_unit", rename = "@DeltaTUnit")] + pub delta_t_unit: UnitsTime, + #[serde( + default, + rename = "@ExposureTime", + skip_serializing_if = "Option::is_none" + )] + pub exposure_time: Option, + #[serde( + default = "Plane::default_exposure_time_unit", + rename = "@ExposureTimeUnit" + )] + pub exposure_time_unit: UnitsTime, + #[serde( + default, + rename = "@PositionX", + skip_serializing_if = "Option::is_none" + )] + pub position_x: Option, + #[serde(default = "Plane::default_position_x_unit", rename = "@PositionXUnit")] + pub position_x_unit: UnitsLength, + #[serde( + default, + rename = "@PositionY", + skip_serializing_if = "Option::is_none" + )] + pub position_y: Option, + #[serde(default = "Plane::default_position_y_unit", rename = "@PositionYUnit")] + pub position_y_unit: UnitsLength, + #[serde( + default, + rename = "@PositionZ", + skip_serializing_if = "Option::is_none" + )] + pub position_z: Option, + #[serde(default = "Plane::default_position_z_unit", rename = "@PositionZUnit")] + pub position_z_unit: UnitsLength, + #[serde(rename = "HashSHA1", skip_serializing_if = "Option::is_none")] + pub hash_sha1: Option, + #[serde(rename = "AnnotationRef", skip_serializing_if = "Option::is_none")] + pub annotation_ref: Option, +} +impl Plane { + pub fn default_delta_t_unit() -> UnitsTime { + UnitsTime::s + } + pub fn default_exposure_time_unit() -> UnitsTime { + UnitsTime::s + } + pub fn default_position_x_unit() -> UnitsLength { + UnitsLength::um + } + pub fn default_position_y_unit() -> UnitsLength { + UnitsLength::um + } + pub fn default_position_z_unit() -> UnitsLength { + UnitsLength::um + } +} +impl Default for Plane { + fn default() -> Self { + Self { + the_z: None, + the_t: None, + the_c: None, + delta_t: None, + delta_t_unit: Self::default_delta_t_unit(), + exposure_time: None, + exposure_time_unit: Self::default_exposure_time_unit(), + position_x: None, + position_x_unit: Self::default_position_x_unit(), + position_y: None, + position_y_unit: Self::default_position_y_unit(), + position_z: None, + position_z_unit: Self::default_position_z_unit(), + hash_sha1: None, + annotation_ref: None, + } + } +} + +#[cfg_attr( + feature = "python", + pyclass( + module = "ome_metadata", + skip_from_py_object, + get_all, + set_all, + eq, + new = "from_fields" + ), + derive(FromPyObject, PyOme) +)] +#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, OmeXML)] +pub struct Plate { + #[serde(rename = "@ID")] + pub id: String, + #[serde(default, rename = "@Name", skip_serializing_if = "Option::is_none")] + pub name: Option, + #[serde(default, rename = "@Status", skip_serializing_if = "Option::is_none")] + pub status: Option, + #[serde( + default, + rename = "@ExternalIdentifier", + skip_serializing_if = "Option::is_none" + )] + pub external_identifier: Option, + #[serde( + default, + rename = "@ColumnNamingConvention", + skip_serializing_if = "Option::is_none" + )] + pub column_naming_convention: Option, + #[serde( + default, + rename = "@RowNamingConvention", + skip_serializing_if = "Option::is_none" + )] + pub row_naming_convention: Option, + #[serde( + default, + rename = "@WellOriginX", + skip_serializing_if = "Option::is_none" + )] + pub well_origin_x: Option, + #[serde( + default = "Plate::default_well_origin_x_unit", + rename = "@WellOriginXUnit" + )] + pub well_origin_x_unit: UnitsLength, + #[serde( + default, + rename = "@WellOriginY", + skip_serializing_if = "Option::is_none" + )] + pub well_origin_y: Option, + #[serde( + default = "Plate::default_well_origin_y_unit", + rename = "@WellOriginYUnit" + )] + pub well_origin_y_unit: UnitsLength, + #[serde(default, rename = "@Rows", skip_serializing_if = "Option::is_none")] + pub rows: Option, + #[serde(default, rename = "@Columns", skip_serializing_if = "Option::is_none")] + pub columns: Option, + #[serde( + default, + rename = "@FieldIndex", + skip_serializing_if = "Option::is_none" + )] + pub field_index: Option, + #[serde( + default, + rename = "Description", + skip_serializing_if = "Option::is_none" + )] + pub description: Option, + #[serde(default, rename = "Well", skip_serializing_if = "Vec::is_empty")] + pub well: Vec, + #[serde( + default, + rename = "AnnotationRef", + skip_serializing_if = "Vec::is_empty" + )] + pub annotation_ref: Vec, + #[serde( + default, + rename = "PlateAcquisition", + skip_serializing_if = "Vec::is_empty" + )] + pub plate_acquisition: Vec, +} +impl Plate { + pub fn default_well_origin_x_unit() -> UnitsLength { + UnitsLength::um + } + pub fn default_well_origin_y_unit() -> UnitsLength { + UnitsLength::um + } +} +impl Default for Plate { + fn default() -> Self { + Self { + id: String::new(), + name: None, + status: None, + external_identifier: None, + column_naming_convention: None, + row_naming_convention: None, + well_origin_x: None, + well_origin_x_unit: Self::default_well_origin_x_unit(), + well_origin_y: None, + well_origin_y_unit: Self::default_well_origin_y_unit(), + rows: None, + columns: None, + field_index: None, + description: None, + well: Vec::new(), + annotation_ref: Vec::new(), + plate_acquisition: Vec::new(), + } + } +} +#[cfg_attr( + feature = "python", + pyclass( + module = "ome_metadata", + skip_from_py_object, + get_all, + set_all, + eq, + new = "from_fields" + ), + derive(FromPyObject, PyOme) +)] +#[derive(Clone, Debug, Serialize, Deserialize, Default, PartialEq, OmeXML)] +pub struct PlateAcquisition { + #[serde(rename = "@ID")] + pub id: String, + #[serde(default, rename = "@Name", skip_serializing_if = "Option::is_none")] + pub name: Option, + #[serde(default, rename = "@EndTime", skip_serializing_if = "Option::is_none")] + pub end_time: Option, + #[serde( + default, + rename = "@StartTime", + skip_serializing_if = "Option::is_none" + )] + pub start_time: Option, + #[serde( + default, + rename = "@MaximumFieldCount", + skip_serializing_if = "Option::is_none" + )] + pub maximum_field_count: Option, + #[serde( + default, + rename = "Description", + skip_serializing_if = "Option::is_none" + )] + pub description: Option, + #[serde( + default, + rename = "WellSampleRef", + skip_serializing_if = "Vec::is_empty" + )] + pub well_sample_ref: Vec, + #[serde( + default, + rename = "AnnotationRef", + skip_serializing_if = "Vec::is_empty" + )] + pub annotation_ref: Vec, +} +#[cfg_attr( + feature = "python", + pyclass( + module = "ome_metadata", + skip_from_py_object, + get_all, + set_all, + eq, + new = "from_fields" + ), + derive(FromPyObject, PyOme) +)] +#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, OmeXML)] +pub struct Polygon { + #[serde( + default, + rename = "@FillColor", + skip_serializing_if = "Option::is_none" + )] + pub fill_color: Option, + #[serde(default, rename = "@FillRule", skip_serializing_if = "Option::is_none")] + pub fill_rule: Option, + #[serde( + default, + rename = "@StrokeColor", + skip_serializing_if = "Option::is_none" + )] + pub stroke_color: Option, + #[serde( + default, + rename = "@StrokeWidth", + skip_serializing_if = "Option::is_none" + )] + pub stroke_width: Option, + #[serde( + default = "Polygon::default_stroke_width_unit", + rename = "@StrokeWidthUnit" + )] + pub stroke_width_unit: UnitsLength, + #[serde( + default, + rename = "@StrokeDashArray", + skip_serializing_if = "Option::is_none" + )] + pub stroke_dash_array: Option, + #[serde(default, rename = "@Text", skip_serializing_if = "Option::is_none")] + pub text: Option, + #[serde( + default, + rename = "@FontFamily", + skip_serializing_if = "Option::is_none" + )] + pub font_family: Option, + #[serde(default, rename = "@FontSize", skip_serializing_if = "Option::is_none")] + pub font_size: Option, + #[serde(default = "Polygon::default_font_size_unit", rename = "@FontSizeUnit")] + pub font_size_unit: UnitsLength, + #[serde( + default, + rename = "@FontStyle", + skip_serializing_if = "Option::is_none" + )] + pub font_style: Option, + #[serde(default, rename = "@Locked", skip_serializing_if = "Option::is_none")] + pub locked: Option, + #[serde(rename = "@ID")] + pub id: String, + #[serde(default, rename = "@TheZ", skip_serializing_if = "Option::is_none")] + pub the_z: Option, + #[serde(default, rename = "@TheT", skip_serializing_if = "Option::is_none")] + pub the_t: Option, + #[serde(default, rename = "@TheC", skip_serializing_if = "Option::is_none")] + pub the_c: Option, + #[serde(rename = "@Points")] + pub points: String, + #[serde(default, rename = "Transform", skip_serializing_if = "Option::is_none")] + pub transform: Option, + #[serde( + default, + rename = "AnnotationRef", + skip_serializing_if = "Vec::is_empty" + )] + pub annotation_ref: Vec, +} +impl Polygon { + pub fn default_stroke_width_unit() -> UnitsLength { + UnitsLength::Pixel + } + pub fn default_font_size_unit() -> UnitsLength { + UnitsLength::Pixel + } +} +impl Default for Polygon { + fn default() -> Self { + Self { + fill_color: None, + fill_rule: None, + stroke_color: None, + stroke_width: None, + stroke_width_unit: Self::default_stroke_width_unit(), + stroke_dash_array: None, + text: None, + font_family: None, + font_size: None, + font_size_unit: Self::default_font_size_unit(), + font_style: None, + locked: None, + id: String::new(), + the_z: None, + the_c: None, + the_t: None, + points: String::new(), + transform: None, + annotation_ref: Vec::new(), + } + } +} +#[cfg_attr( + feature = "python", + pyclass( + module = "ome_metadata", + skip_from_py_object, + get_all, + set_all, + eq, + new = "from_fields" + ), + derive(FromPyObject, PyOme) +)] +#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, OmeXML)] +pub struct Polyline { + #[serde( + default, + rename = "@FillColor", + skip_serializing_if = "Option::is_none" + )] + pub fill_color: Option, + #[serde(default, rename = "@FillRule", skip_serializing_if = "Option::is_none")] + pub fill_rule: Option, + #[serde( + default, + rename = "@StrokeColor", + skip_serializing_if = "Option::is_none" + )] + pub stroke_color: Option, + #[serde( + default, + rename = "@StrokeWidth", + skip_serializing_if = "Option::is_none" + )] + pub stroke_width: Option, + #[serde( + default = "Polyline::default_stroke_width_unit", + rename = "@StrokeWidthUnit" + )] + pub stroke_width_unit: UnitsLength, + #[serde( + default, + rename = "@StrokeDashArray", + skip_serializing_if = "Option::is_none" + )] + pub stroke_dash_array: Option, + #[serde(default, rename = "@Text", skip_serializing_if = "Option::is_none")] + pub text: Option, + #[serde( + default, + rename = "@FontFamily", + skip_serializing_if = "Option::is_none" + )] + pub font_family: Option, + #[serde(default, rename = "@FontSize", skip_serializing_if = "Option::is_none")] + pub font_size: Option, + #[serde(default = "Polyline::default_font_size_unit", rename = "@FontSizeUnit")] + pub font_size_unit: UnitsLength, + #[serde( + default, + rename = "@FontStyle", + skip_serializing_if = "Option::is_none" + )] + pub font_style: Option, + #[serde(default, rename = "@Locked", skip_serializing_if = "Option::is_none")] + pub locked: Option, + #[serde(rename = "@ID")] + pub id: String, + #[serde(default, rename = "@TheZ", skip_serializing_if = "Option::is_none")] + pub the_z: Option, + #[serde(default, rename = "@TheT", skip_serializing_if = "Option::is_none")] + pub the_t: Option, + #[serde(default, rename = "@TheC", skip_serializing_if = "Option::is_none")] + pub the_c: Option, + #[serde(rename = "@Points")] + pub points: String, + #[serde( + default, + rename = "@MarkerStart", + skip_serializing_if = "Option::is_none" + )] + pub marker_start: Option, + #[serde( + default, + rename = "@MarkerEnd", + skip_serializing_if = "Option::is_none" + )] + pub marker_end: Option, + #[serde(default, rename = "Transform", skip_serializing_if = "Option::is_none")] + pub transform: Option, + #[serde( + default, + rename = "AnnotationRef", + skip_serializing_if = "Vec::is_empty" + )] + pub annotation_ref: Vec, +} +impl Polyline { + pub fn default_stroke_width_unit() -> UnitsLength { + UnitsLength::Pixel + } + pub fn default_font_size_unit() -> UnitsLength { + UnitsLength::Pixel + } +} +impl Default for Polyline { + fn default() -> Self { + Self { + fill_color: None, + fill_rule: None, + stroke_color: None, + stroke_width: None, + stroke_width_unit: Self::default_stroke_width_unit(), + stroke_dash_array: None, + text: None, + font_family: None, + font_size: None, + font_size_unit: Self::default_font_size_unit(), + font_style: None, + locked: None, + id: String::new(), + the_z: None, + the_c: None, + the_t: None, + points: String::new(), + marker_start: None, + marker_end: None, + transform: None, + annotation_ref: Vec::new(), + } + } +} +#[cfg_attr( + feature = "python", + pyclass( + module = "ome_metadata", + skip_from_py_object, + get_all, + set_all, + eq, + new = "from_fields" + ), + derive(FromPyObject, PyOme) +)] +#[derive(Clone, Debug, Serialize, Deserialize, Default, PartialEq, OmeXML)] +pub struct Project { + #[serde(default, rename = "@Name", skip_serializing_if = "Option::is_none")] + pub name: Option, + #[serde(rename = "@ID")] + pub id: String, + #[serde( + default, + rename = "Description", + skip_serializing_if = "Option::is_none" + )] + pub description: Option, + #[serde( + default, + rename = "ExperimenterRef", + skip_serializing_if = "Option::is_none" + )] + pub experimenter_ref: Option, + #[serde( + default, + rename = "ExperimenterGroupRef", + skip_serializing_if = "Option::is_none" + )] + pub experimenter_group_ref: Option, + #[serde(default, rename = "DatasetRef", skip_serializing_if = "Vec::is_empty")] + pub dataset_ref: Vec, + #[serde( + default, + rename = "AnnotationRef", + skip_serializing_if = "Vec::is_empty" + )] + pub annotation_ref: Vec, +} +#[cfg_attr( + feature = "python", + pyclass( + module = "ome_metadata", + skip_from_py_object, + get_all, + set_all, + eq, + new = "from_fields" + ), + derive(FromPyObject, PyOme) +)] +#[derive(Clone, Debug, Serialize, Deserialize, Default, PartialEq, OmeXML)] +pub struct Roi { + #[serde(rename = "@ID")] + pub id: String, + #[serde(default, rename = "@Name", skip_serializing_if = "Option::is_none")] + pub name: Option, + #[serde(rename = "Union", skip_serializing_if = "Option::is_none")] + pub union: Option, + #[serde(rename = "AnnotationRef", skip_serializing_if = "Option::is_none")] + pub annotation_ref: Option, + #[serde(rename = "Description", skip_serializing_if = "Option::is_none")] + pub description: Option, +} +#[cfg_attr( + feature = "python", + pyclass( + module = "ome_metadata", + skip_from_py_object, + get_all, + set_all, + eq, + new = "from_fields" + ), + derive(FromPyObject, PyOme) +)] +#[derive(Clone, Debug, Serialize, Deserialize, Default, PartialEq, OmeXML)] +pub struct Reagent { + #[serde(rename = "@ID")] + pub id: String, + #[serde(default, rename = "@Name", skip_serializing_if = "Option::is_none")] + pub name: Option, + #[serde( + default, + rename = "@ReagentIdentifier", + skip_serializing_if = "Option::is_none" + )] + pub reagent_identifier: Option, + #[serde( + default, + rename = "Description", + skip_serializing_if = "Option::is_none" + )] + pub description: Option, + #[serde( + default, + rename = "AnnotationRef", + skip_serializing_if = "Vec::is_empty" + )] + pub annotation_ref: Vec, +} +#[cfg_attr( + feature = "python", + pyclass( + module = "ome_metadata", + skip_from_py_object, + get_all, + set_all, + eq, + new = "from_fields" + ), + derive(FromPyObject, PyOme) +)] +#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, OmeXML)] +pub struct Rectangle { + #[serde( + default, + rename = "@FillColor", + skip_serializing_if = "Option::is_none" + )] + pub fill_color: Option, + #[serde(default, rename = "@FillRule", skip_serializing_if = "Option::is_none")] + pub fill_rule: Option, + #[serde( + default, + rename = "@StrokeColor", + skip_serializing_if = "Option::is_none" + )] + pub stroke_color: Option, + #[serde( + default, + rename = "@StrokeWidth", + skip_serializing_if = "Option::is_none" + )] + pub stroke_width: Option, + #[serde( + default = "Rectangle::default_stroke_width_unit", + rename = "@StrokeWidthUnit" + )] + pub stroke_width_unit: UnitsLength, + #[serde( + default, + rename = "@StrokeDashArray", + skip_serializing_if = "Option::is_none" + )] + pub stroke_dash_array: Option, + #[serde(default, rename = "@Text", skip_serializing_if = "Option::is_none")] + pub text: Option, + #[serde( + default, + rename = "@FontFamily", + skip_serializing_if = "Option::is_none" + )] + pub font_family: Option, + #[serde(default, rename = "@FontSize", skip_serializing_if = "Option::is_none")] + pub font_size: Option, + #[serde( + default = "Rectangle::default_font_size_unit", + rename = "@FontSizeUnit" + )] + pub font_size_unit: UnitsLength, + #[serde( + default, + rename = "@FontStyle", + skip_serializing_if = "Option::is_none" + )] + pub font_style: Option, + #[serde(default, rename = "@Locked", skip_serializing_if = "Option::is_none")] + pub locked: Option, + #[serde(rename = "@ID")] + pub id: String, + #[serde(default, rename = "@TheZ", skip_serializing_if = "Option::is_none")] + pub the_z: Option, + #[serde(default, rename = "@TheT", skip_serializing_if = "Option::is_none")] + pub the_t: Option, + #[serde(default, rename = "@TheC", skip_serializing_if = "Option::is_none")] + pub the_c: Option, + #[serde(rename = "@X")] + pub x: f32, + #[serde(rename = "@Y")] + pub y: f32, + #[serde(rename = "@Width")] + pub width: f32, + #[serde(rename = "@Height")] + pub height: f32, + #[serde(default, rename = "Transform", skip_serializing_if = "Option::is_none")] + pub transform: Option, + #[serde( + default, + rename = "AnnotationRef", + skip_serializing_if = "Vec::is_empty" + )] + pub annotation_ref: Vec, +} +impl Rectangle { + pub fn default_stroke_width_unit() -> UnitsLength { + UnitsLength::Pixel + } + pub fn default_font_size_unit() -> UnitsLength { + UnitsLength::Pixel + } +} +impl Default for Rectangle { + fn default() -> Self { + Self { + fill_color: None, + fill_rule: None, + stroke_color: None, + stroke_width: None, + stroke_width_unit: Self::default_stroke_width_unit(), + stroke_dash_array: None, + text: None, + font_family: None, + font_size: None, + font_size_unit: Self::default_font_size_unit(), + font_style: None, + locked: None, + id: String::new(), + the_z: None, + the_c: None, + x: 0.0, + y: 0.0, + width: 0.0, + the_t: None, + transform: None, + annotation_ref: Vec::new(), + height: 0.0, + } + } +} +#[cfg_attr( + feature = "python", + pyclass( + module = "ome_metadata", + skip_from_py_object, + get_all, + set_all, + eq, + new = "from_fields" + ), + derive(FromPyObject, PyOme) +)] +#[derive(Clone, Debug, Serialize, Deserialize, Default, PartialEq, OmeXML)] +pub struct Rights { + #[serde( + default, + rename = "RightsHolder", + skip_serializing_if = "Option::is_none" + )] + pub rights_holder: Option, + #[serde( + default, + rename = "RightsHeld", + skip_serializing_if = "Option::is_none" + )] + pub rights_held: Option, +} +#[cfg_attr( + feature = "python", + pyclass( + module = "ome_metadata", + skip_from_py_object, + get_all, + set_all, + eq, + new = "from_fields" + ), + derive(FromPyObject, PyOme) +)] +#[derive(Clone, Debug, Serialize, Deserialize, Default, PartialEq, OmeXML)] +pub struct RoiUnion { + #[serde(default, rename = "ShapeGroup", skip_serializing_if = "Vec::is_empty")] + pub shape_group: Vec, +} +#[cfg_attr( + feature = "python", + pyclass( + module = "ome_metadata", + skip_from_py_object, + get_all, + set_all, + eq, + new = "from_fields" + ), + derive(FromPyObject, PyOme) +)] +#[derive(Clone, Debug, Serialize, Deserialize, Default, PartialEq, OmeXML)] +pub struct Screen { + #[serde(rename = "@ID")] + pub id: String, + #[serde(default, rename = "@Name", skip_serializing_if = "Option::is_none")] + pub name: Option, + #[serde( + default, + rename = "@ProtocolIdentifier", + skip_serializing_if = "Option::is_none" + )] + pub protocol_identifier: Option, + #[serde( + default, + rename = "@ProtocolDescription", + skip_serializing_if = "Option::is_none" + )] + pub protocol_description: Option, + #[serde( + default, + rename = "@ReagentSetDescription", + skip_serializing_if = "Option::is_none" + )] + pub reagent_set_description: Option, + #[serde( + default, + rename = "@ReagentSetIdentifier", + skip_serializing_if = "Option::is_none" + )] + pub reagent_set_identifier: Option, + #[serde(default, rename = "@Type", skip_serializing_if = "Option::is_none")] + pub r#type: Option, + #[serde( + default, + rename = "Description", + skip_serializing_if = "Option::is_none" + )] + pub description: Option, + #[serde(default, rename = "Reagent", skip_serializing_if = "Vec::is_empty")] + pub reagent: Vec, + #[serde(default, rename = "PlateRef", skip_serializing_if = "Vec::is_empty")] + pub plate_ref: Vec, + #[serde( + default, + rename = "AnnotationRef", + skip_serializing_if = "Vec::is_empty" + )] + pub annotation_ref: Vec, +} +#[cfg_attr( + feature = "python", + pyclass( + module = "ome_metadata", + skip_from_py_object, + get_all, + set_all, + eq, + new = "from_fields" + ), + derive(FromPyObject, PyOme) +)] +#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, OmeXML)] +pub struct ShapeType { + #[serde( + default, + rename = "@FillColor", + skip_serializing_if = "Option::is_none" + )] + pub fill_color: Option, + #[serde(default, rename = "@FillRule", skip_serializing_if = "Option::is_none")] + pub fill_rule: Option, + #[serde( + default, + rename = "@StrokeColor", + skip_serializing_if = "Option::is_none" + )] + pub stroke_color: Option, + #[serde( + default, + rename = "@StrokeWidth", + skip_serializing_if = "Option::is_none" + )] + pub stroke_width: Option, + #[serde( + default = "ShapeType::default_stroke_width_unit", + rename = "@StrokeWidthUnit" + )] + pub stroke_width_unit: UnitsLength, + #[serde( + default, + rename = "@StrokeDashArray", + skip_serializing_if = "Option::is_none" + )] + pub stroke_dash_array: Option, + #[serde(default, rename = "@Text", skip_serializing_if = "Option::is_none")] + pub text: Option, + #[serde( + default, + rename = "@FontFamily", + skip_serializing_if = "Option::is_none" + )] + pub font_family: Option, + #[serde(default, rename = "@FontSize", skip_serializing_if = "Option::is_none")] + pub font_size: Option, + #[serde( + default = "ShapeType::default_font_size_unit", + rename = "@FontSizeUnit" + )] + pub font_size_unit: UnitsLength, + #[serde( + default, + rename = "@FontStyle", + skip_serializing_if = "Option::is_none" + )] + pub font_style: Option, + #[serde(default, rename = "@Locked", skip_serializing_if = "Option::is_none")] + pub locked: Option, + #[serde(rename = "@ID")] + pub id: String, + #[serde(default, rename = "@TheZ", skip_serializing_if = "Option::is_none")] + pub the_z: Option, + #[serde(default, rename = "@TheT", skip_serializing_if = "Option::is_none")] + pub the_t: Option, + #[serde(default, rename = "@TheC", skip_serializing_if = "Option::is_none")] + pub the_c: Option, + #[serde(default, rename = "Transform", skip_serializing_if = "Option::is_none")] + pub transform: Option, + #[serde( + default, + rename = "AnnotationRef", + skip_serializing_if = "Vec::is_empty" + )] + pub annotation_ref: Vec, +} +impl ShapeType { + pub fn default_stroke_width_unit() -> UnitsLength { + UnitsLength::Pixel + } + pub fn default_font_size_unit() -> UnitsLength { + UnitsLength::Pixel + } +} +impl Default for ShapeType { + fn default() -> Self { + Self { + fill_color: None, + fill_rule: None, + stroke_color: None, + stroke_width: None, + stroke_width_unit: Self::default_stroke_width_unit(), + stroke_dash_array: None, + text: None, + font_family: None, + font_size: None, + font_size_unit: Self::default_font_size_unit(), + font_style: None, + locked: None, + id: String::new(), + the_z: None, + the_t: None, + the_c: None, + transform: None, + annotation_ref: Vec::new(), + } + } +} +#[derive( + EnumString, + AsRefStr, + Debug, + strum::Display, + Clone, + Copy, + PartialEq, + Eq, + PartialOrd, + Ord, + Hash, + Deserialize, + Serialize, + VariantNames, + OmeXML, +)] +#[strum(ascii_case_insensitive)] +#[cfg_attr( + feature = "python", + pyclass(module = "ome_metadata", from_py_object, get_all, set_all, eq), + derive(PyOmeEnum) +)] +pub enum ShapeFillRuleType { + #[serde(rename = "EvenOdd")] + EvenOdd, + #[serde(rename = "NonZero")] + NonZero, +} +#[derive( + EnumString, + AsRefStr, + Debug, + strum::Display, + Clone, + Copy, + PartialEq, + Eq, + PartialOrd, + Ord, + Hash, + Deserialize, + Serialize, + VariantNames, + OmeXML, +)] +#[strum(ascii_case_insensitive)] +#[cfg_attr( + feature = "python", + pyclass(module = "ome_metadata", from_py_object, get_all, set_all, eq), + derive(PyOmeEnum) +)] +pub enum ShapeFontStyleType { + #[serde(rename = "Bold")] + Bold, + #[serde(rename = "BoldItalic")] + BoldItalic, + #[serde(rename = "Italic")] + Italic, + #[serde(rename = "Normal")] + Normal, +} +#[derive( + AsRefStr, Debug, strum::Display, Clone, PartialEq, Deserialize, Serialize, VariantNames, OmeXML, +)] +#[strum(ascii_case_insensitive)] +#[cfg_attr( + feature = "python", + pyclass(module = "ome_metadata", from_py_object, get_all, set_all, eq), + derive(PyOmeComplexEnum) +)] +pub enum ShapeGroup { + #[serde(rename = "Rectangle")] + Rectangle(Rectangle), + #[serde(rename = "Mask")] + Mask(Mask), + #[serde(rename = "Point")] + Point(Label), + #[serde(rename = "Ellipse")] + Ellipse(Ellipse), + #[serde(rename = "Line")] + Line(Line), + #[serde(rename = "Polyline")] + Polyline(Polyline), + #[serde(rename = "Polygon")] + Polygon(Polygon), + #[serde(rename = "Label")] + Label(Label), +} +#[cfg_attr( + feature = "python", + pyclass( + module = "ome_metadata", + skip_from_py_object, + get_all, + set_all, + eq, + new = "from_fields" + ), + derive(FromPyObject, PyOme) +)] +#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, OmeXML)] +pub struct StageLabel { + #[serde(rename = "@Name")] + pub name: String, + #[serde(default, rename = "@X", skip_serializing_if = "Option::is_none")] + pub x: Option, + #[serde(default = "StageLabel::default_x_unit", rename = "@XUnit")] + pub x_unit: UnitsLength, + #[serde(default, rename = "@Y", skip_serializing_if = "Option::is_none")] + pub y: Option, + #[serde(default = "StageLabel::default_y_unit", rename = "@YUnit")] + pub y_unit: UnitsLength, + #[serde(default, rename = "@Z", skip_serializing_if = "Option::is_none")] + pub z: Option, + #[serde(default = "StageLabel::default_z_unit", rename = "@ZUnit")] + pub z_unit: UnitsLength, +} +impl StageLabel { + pub fn default_x_unit() -> UnitsLength { + UnitsLength::um + } + pub fn default_y_unit() -> UnitsLength { + UnitsLength::um + } + pub fn default_z_unit() -> UnitsLength { + UnitsLength::um + } +} +impl Default for StageLabel { + fn default() -> Self { + Self { + name: String::new(), + x: None, + x_unit: Self::default_x_unit(), + y: None, + y_unit: Self::default_y_unit(), + z: None, + z_unit: Self::default_z_unit(), + } + } +} +#[cfg_attr( + feature = "python", + pyclass( + module = "ome_metadata", + skip_from_py_object, + get_all, + set_all, + eq, + new = "from_fields" + ), + derive(FromPyObject, PyOme) +)] +#[derive(Clone, Debug, Serialize, Deserialize, Default, PartialEq, OmeXML)] +pub struct StructuredAnnotations { + #[serde(default, rename = "$value", skip_serializing_if = "Option::is_none")] + pub content: Option, +} +#[allow(clippy::enum_variant_names)] +#[derive( + AsRefStr, Debug, strum::Display, Clone, PartialEq, Deserialize, Serialize, VariantNames, OmeXML, +)] +#[strum(ascii_case_insensitive)] +#[cfg_attr( + feature = "python", + pyclass(module = "ome_metadata", from_py_object, get_all, set_all, eq), + derive(PyOmeComplexEnum) +)] +pub enum StructuredAnnotationsContent { + #[serde(rename = "XMLAnnotation")] + XmlAnnotation(XmlAnnotation), + #[serde(rename = "FileAnnotation")] + FileAnnotation(FileAnnotation), + #[serde(rename = "ListAnnotation")] + ListAnnotation(Annotation), + #[serde(rename = "LongAnnotation")] + LongAnnotation(LongAnnotation), + #[serde(rename = "DoubleAnnotation")] + DoubleAnnotation(DoubleAnnotation), + #[serde(rename = "CommentAnnotation")] + CommentAnnotation(CommentAnnotation), + #[serde(rename = "BooleanAnnotation")] + BooleanAnnotation(BooleanAnnotation), + #[serde(rename = "TimestampAnnotation")] + TimestampAnnotation(CommentAnnotation), + #[serde(rename = "TagAnnotation")] + TagAnnotation(CommentAnnotation), + #[serde(rename = "TermAnnotation")] + TermAnnotation(CommentAnnotation), + #[serde(rename = "MapAnnotation")] + MapAnnotation(MapAnnotation), +} +#[cfg_attr( + feature = "python", + pyclass( + module = "ome_metadata", + skip_from_py_object, + get_all, + set_all, + eq, + new = "from_fields" + ), + derive(FromPyObject, PyOme) +)] +#[derive(Clone, Debug, Serialize, Deserialize, Default, PartialEq, OmeXML)] +pub struct TiffData { + #[serde(default = "TiffData::default_ifd", rename = "@IFD")] + pub ifd: i32, + #[serde(default = "TiffData::default_first_z", rename = "@FirstZ")] + pub first_z: i32, + #[serde(default = "TiffData::default_first_t", rename = "@FirstT")] + pub first_t: i32, + #[serde(default = "TiffData::default_first_c", rename = "@FirstC")] + pub first_c: i32, + #[serde( + default, + rename = "@PlaneCount", + skip_serializing_if = "Option::is_none" + )] + pub plane_count: Option, + #[serde(default, rename = "UUID", skip_serializing_if = "Option::is_none")] + pub uuid: Option, +} +impl TiffData { + pub fn default_ifd() -> i32 { + 0 + } + pub fn default_first_z() -> i32 { + 0 + } + pub fn default_first_t() -> i32 { + 0 + } + pub fn default_first_c() -> i32 { + 0 + } +} +#[cfg_attr( + feature = "python", + pyclass( + module = "ome_metadata", + skip_from_py_object, + get_all, + set_all, + eq, + new = "from_fields" + ), + derive(FromPyObject, PyOme) +)] +#[derive(Clone, Debug, Serialize, Deserialize, Default, PartialEq, OmeXML)] +pub struct TiffDataUuid { + #[serde(default, rename = "@FileName", skip_serializing_if = "Option::is_none")] + pub file_name: Option, + #[serde(rename = "$text")] + pub content: String, +} +#[cfg_attr( + feature = "python", + pyclass( + module = "ome_metadata", + skip_from_py_object, + get_all, + set_all, + eq, + new = "from_fields" + ), + derive(FromPyObject, PyOme) +)] +#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, OmeXML)] +pub struct TransmittanceRange { + #[serde(default, rename = "@CutIn", skip_serializing_if = "Option::is_none")] + pub cut_in: Option, + #[serde( + default = "TransmittanceRange::default_cut_in_unit", + rename = "@CutInUnit" + )] + pub cut_in_unit: UnitsLength, + #[serde(default, rename = "@CutOut", skip_serializing_if = "Option::is_none")] + pub cut_out: Option, + #[serde( + default = "TransmittanceRange::default_cut_out_unit", + rename = "@CutOutUnit" + )] + pub cut_out_unit: UnitsLength, + #[serde( + default, + rename = "@CutInTolerance", + skip_serializing_if = "Option::is_none" + )] + pub cut_in_tolerance: Option, + #[serde( + default = "TransmittanceRange::default_cut_in_tolerance_unit", + rename = "@CutInToleranceUnit" + )] + pub cut_in_tolerance_unit: UnitsLength, + #[serde( + default, + rename = "@CutOutTolerance", + skip_serializing_if = "Option::is_none" + )] + pub cut_out_tolerance: Option, + #[serde( + default = "TransmittanceRange::default_cut_out_tolerance_unit", + rename = "@CutOutToleranceUnit" + )] + pub cut_out_tolerance_unit: UnitsLength, + #[serde( + default, + rename = "@Transmittance", + skip_serializing_if = "Option::is_none" + )] + pub transmittance: Option, +} +impl TransmittanceRange { + pub fn default_cut_in_unit() -> UnitsLength { + UnitsLength::m + } + pub fn default_cut_out_unit() -> UnitsLength { + UnitsLength::m + } + pub fn default_cut_in_tolerance_unit() -> UnitsLength { + UnitsLength::m + } + pub fn default_cut_out_tolerance_unit() -> UnitsLength { + UnitsLength::m + } +} +impl Default for TransmittanceRange { + fn default() -> Self { + Self { + cut_in: None, + cut_in_unit: Self::default_cut_in_unit(), + cut_out: None, + cut_out_unit: Self::default_cut_out_unit(), + cut_in_tolerance: None, + cut_in_tolerance_unit: Self::default_cut_in_tolerance_unit(), + cut_out_tolerance: None, + cut_out_tolerance_unit: Self::default_cut_out_tolerance_unit(), + transmittance: None, + } + } +} + +#[derive( + EnumString, + AsRefStr, + Debug, + strum::Display, + Clone, + Copy, + PartialEq, + Eq, + PartialOrd, + Ord, + Hash, + Deserialize, + Serialize, + VariantNames, + OmeXML, +)] +#[strum(ascii_case_insensitive)] +#[cfg_attr( + feature = "python", + pyclass( + module = "ome_metadata", + from_py_object, + get_all, + set_all, + eq, + frozen, + hash + ), + derive(PyOmeUnit) +)] +pub enum UnitsElectricPotential { + YV, + ZV, + EV, + PV, + TV, + GV, + MV, + kV, + hV, + daV, + V, + dV, + cV, + mV, + #[serde(rename = "µV")] + uV, + nV, + pV, + fV, + aV, + zV, + yV, +} +#[derive( + EnumString, + AsRefStr, + Debug, + strum::Display, + Clone, + Copy, + PartialEq, + Eq, + PartialOrd, + Ord, + Hash, + Deserialize, + Serialize, + VariantNames, + OmeXML, +)] +#[strum(ascii_case_insensitive)] +#[cfg_attr( + feature = "python", + pyclass( + module = "ome_metadata", + from_py_object, + get_all, + set_all, + eq, + frozen, + hash + ), + derive(PyOmeUnit) +)] +pub enum UnitsFrequency { + YHz, + ZHz, + EHz, + PHz, + THz, + GHz, + MHz, + kHz, + hHz, + daHz, + Hz, + dHz, + cHz, + mHz, + #[serde(rename = "µHz")] + uHz, + nHz, + pHz, + fHz, + aHz, + zHz, + yHz, +} +#[derive( + EnumString, + AsRefStr, + Debug, + strum::Display, + Clone, + Copy, + PartialEq, + Eq, + PartialOrd, + Ord, + Hash, + Deserialize, + Serialize, + VariantNames, + OmeXML, +)] +#[strum(ascii_case_insensitive)] +#[cfg_attr( + feature = "python", + pyclass( + module = "ome_metadata", + from_py_object, + get_all, + set_all, + eq, + frozen, + hash + ), + derive(PyOmeUnit) +)] +pub enum UnitsLength { + Ym, + Zm, + Em, + Pm, + Tm, + Gm, + Mm, + km, + hm, + dam, + m, + dm, + cm, + mm, + #[serde(rename = "µm")] + um, + nm, + pm, + fm, + am, + zm, + ym, + #[serde(rename = "Å")] + A, + #[serde(rename = "thou")] + Thou, + #[serde(rename = "li")] + Li, + #[serde(rename = "in")] + In, + #[serde(rename = "ft")] + Ft, + #[serde(rename = "yd")] + Yd, + #[serde(rename = "mi")] + Mi, + #[serde(rename = "ua")] + Ua, + #[serde(rename = "ly")] + Ly, + #[serde(rename = "pc")] + Pc, + #[serde(rename = "pt")] + Pt, + #[serde(rename = "pixel")] + Pixel, + #[serde(rename = "reference frame")] + ReferenceFrame, +} +#[derive( + EnumString, + AsRefStr, + Debug, + strum::Display, + Clone, + Copy, + PartialEq, + Eq, + PartialOrd, + Ord, + Hash, + Deserialize, + Serialize, + VariantNames, + OmeXML, +)] +#[strum(ascii_case_insensitive)] +#[cfg_attr( + feature = "python", + pyclass( + module = "ome_metadata", + from_py_object, + get_all, + set_all, + eq, + frozen, + hash + ), + derive(PyOmeUnit) +)] +pub enum UnitsPower { + YW, + ZW, + EW, + PW, + TW, + GW, + MW, + kW, + hW, + daW, + W, + dW, + cW, + mW, + #[serde(rename = "µW")] + uW, + nW, + pW, + fW, + aW, + zW, + yW, +} +#[derive( + EnumString, + AsRefStr, + Debug, + strum::Display, + Clone, + Copy, + PartialEq, + Eq, + PartialOrd, + Ord, + Hash, + Deserialize, + Serialize, + VariantNames, + OmeXML, +)] +#[strum(ascii_case_insensitive)] +#[cfg_attr( + feature = "python", + pyclass( + module = "ome_metadata", + from_py_object, + get_all, + set_all, + eq, + frozen, + hash + ), + derive(PyOmeUnit) +)] +pub enum UnitsPressure { + YPa, + ZPa, + EPa, + PPa, + TPa, + GPa, + MPa, + kPa, + hPa, + daPa, + Pa, + dPa, + cPa, + mPa, + #[serde(rename = "µPa")] + uPa, + nPa, + pPa, + fPa, + aPa, + zPa, + yPa, + bar, + Mbar, + kbar, + dbar, + cbar, + mbar, + atm, + psi, + Torr, + mTorr, + #[serde(rename = "mm Hg")] + mmHg, +} +#[derive( + EnumString, + AsRefStr, + Debug, + strum::Display, + Clone, + Copy, + PartialEq, + Eq, + PartialOrd, + Ord, + Hash, + Deserialize, + Serialize, + VariantNames, + OmeXML, +)] +#[strum(ascii_case_insensitive)] +#[cfg_attr( + feature = "python", + pyclass( + module = "ome_metadata", + from_py_object, + get_all, + set_all, + eq, + frozen, + hash + ), + derive(PyOmeUnit) +)] +pub enum UnitsTemperature { + #[serde(rename = "°C")] + C, + #[serde(rename = "°F")] + F, + #[serde(rename = "K")] + K, + #[serde(rename = "°R")] + R, +} +#[derive( + EnumString, + AsRefStr, + Debug, + strum::Display, + Clone, + Copy, + PartialEq, + Eq, + PartialOrd, + Ord, + Hash, + Deserialize, + Serialize, + VariantNames, + OmeXML, +)] +#[strum(ascii_case_insensitive)] +#[cfg_attr( + feature = "python", + pyclass( + module = "ome_metadata", + from_py_object, + get_all, + set_all, + eq, + frozen, + hash + ), + derive(PyOmeUnit) +)] +pub enum UnitsTime { + Ys, + Zs, + Es, + Ps, + Ts, + Gs, + Ms, + ks, + hs, + das, + s, + ds, + cs, + ms, + #[serde(rename = "µs")] + us, + ns, + ps, + fs, + r#as, + zs, + ys, + min, + h, + d, +} +#[cfg_attr( + feature = "python", + pyclass( + module = "ome_metadata", + skip_from_py_object, + get_all, + set_all, + eq, + new = "from_fields" + ), + derive(FromPyObject, PyOme) +)] +#[derive(Clone, Debug, Serialize, Deserialize, Default, PartialEq, OmeXML)] +pub struct Well { + #[serde(rename = "@ID")] + pub id: String, + #[serde(rename = "@Column")] + pub column: i32, + #[serde(rename = "@Row")] + pub row: i32, + #[serde( + default, + rename = "@ExternalDescription", + skip_serializing_if = "Option::is_none" + )] + pub external_description: Option, + #[serde( + default, + rename = "@ExternalIdentifier", + skip_serializing_if = "Option::is_none" + )] + pub external_identifier: Option, + #[serde(default, rename = "@Type", skip_serializing_if = "Option::is_none")] + pub r#type: Option, + #[serde(default = "Well::default_color", rename = "@Color")] + pub color: i32, + #[serde(default, rename = "WellSample", skip_serializing_if = "Vec::is_empty")] + pub well_sample: Vec, + #[serde( + default, + rename = "ReagentRef", + skip_serializing_if = "Option::is_none" + )] + pub reagent_ref: Option, + #[serde( + default, + rename = "AnnotationRef", + skip_serializing_if = "Vec::is_empty" + )] + pub annotation_ref: Vec, +} +impl Well { + pub fn default_color() -> i32 { + 0 + } +} +#[cfg_attr( + feature = "python", + pyclass( + module = "ome_metadata", + skip_from_py_object, + get_all, + set_all, + eq, + new = "from_fields" + ), + derive(FromPyObject, PyOme) +)] +#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, OmeXML)] +pub struct WellSample { + #[serde(rename = "@ID")] + pub id: String, + #[serde( + default, + rename = "@PositionX", + skip_serializing_if = "Option::is_none" + )] + pub position_x: Option, + #[serde( + default = "WellSample::default_position_x_unit", + rename = "@PositionXUnit" + )] + pub position_x_unit: UnitsLength, + #[serde( + default, + rename = "@PositionY", + skip_serializing_if = "Option::is_none" + )] + pub position_y: Option, + #[serde( + default = "WellSample::default_position_y_unit", + rename = "@PositionYUnit" + )] + pub position_y_unit: UnitsLength, + #[serde( + default, + rename = "@Timepoint", + skip_serializing_if = "Option::is_none" + )] + pub timepoint: Option, + #[serde(rename = "@Index")] + pub index: i32, + #[serde(default, rename = "ImageRef", skip_serializing_if = "Option::is_none")] + pub image_ref: Option, +} +impl WellSample { + pub fn default_position_x_unit() -> UnitsLength { + UnitsLength::um + } + pub fn default_position_y_unit() -> UnitsLength { + UnitsLength::um + } +} +impl Default for WellSample { + fn default() -> Self { + Self { + id: "".to_string(), + position_x: None, + position_x_unit: Self::default_position_x_unit(), + position_y: None, + position_y_unit: Self::default_position_y_unit(), + timepoint: None, + index: 0, + image_ref: None, + } + } +} +#[cfg_attr( + feature = "python", + pyclass( + module = "ome_metadata", + skip_from_py_object, + get_all, + set_all, + eq, + new = "from_fields" + ), + derive(FromPyObject, PyOme) +)] +#[derive(Clone, Debug, Serialize, Deserialize, Default, PartialEq, OmeXML)] +pub struct XmlAnnotation { + #[serde(rename = "@ID")] + pub id: String, + #[serde( + default, + rename = "@Namespace", + skip_serializing_if = "Option::is_none" + )] + pub namespace: Option, + #[serde( + default, + rename = "@Annotator", + skip_serializing_if = "Option::is_none" + )] + pub annotator: Option, + #[serde( + default, + rename = "Description", + skip_serializing_if = "Option::is_none" + )] + pub description: Option, + #[serde( + default, + rename = "AnnotationRef", + skip_serializing_if = "Vec::is_empty" + )] + pub annotation_ref: Vec, + #[serde(rename = "Value")] + pub value: XmlAnnotationValue, +} +#[cfg_attr( + feature = "python", + pyclass(module = "ome_metadata", skip_from_py_object, eq, new = "from_fields") +)] +#[derive(Clone, Debug, Serialize, Deserialize, Default, PartialEq, OmeXML)] +pub struct XmlAnnotationValue; +pub trait Convert: PartialEq { + /// conversion factor between this and SI value + fn as_si(&self) -> Result; + + /// convert a value with this unit into another unit + fn convert(&self, unit: &Self, value: f64) -> Result { + if self == unit { + Ok(value) + } else { + Ok(value * self.as_si()? / unit.as_si()?) + } + } +} + +impl Convert for UnitsElectricPotential { + fn as_si(&self) -> Result { + match self { + UnitsElectricPotential::YV => Ok(1e24), + UnitsElectricPotential::ZV => Ok(1e21), + UnitsElectricPotential::EV => Ok(1e18), + UnitsElectricPotential::PV => Ok(1e15), + UnitsElectricPotential::TV => Ok(1e12), + UnitsElectricPotential::GV => Ok(1e9), + UnitsElectricPotential::MV => Ok(1e6), + UnitsElectricPotential::kV => Ok(1e3), + UnitsElectricPotential::hV => Ok(1e2), + UnitsElectricPotential::daV => Ok(1e1), + UnitsElectricPotential::V => Ok(1e0), + UnitsElectricPotential::dV => Ok(1e-1), + UnitsElectricPotential::cV => Ok(1e-2), + UnitsElectricPotential::mV => Ok(1e-3), + UnitsElectricPotential::uV => Ok(1e-6), + UnitsElectricPotential::nV => Ok(1e-9), + UnitsElectricPotential::pV => Ok(1e-12), + UnitsElectricPotential::fV => Ok(1e-15), + UnitsElectricPotential::aV => Ok(1e-18), + UnitsElectricPotential::zV => Ok(1e-21), + UnitsElectricPotential::yV => Ok(1e-24), + } + } +} + +impl Convert for UnitsFrequency { + fn as_si(&self) -> Result { + match self { + UnitsFrequency::YHz => Ok(1e24), + UnitsFrequency::ZHz => Ok(1e21), + UnitsFrequency::EHz => Ok(1e18), + UnitsFrequency::PHz => Ok(1e15), + UnitsFrequency::THz => Ok(1e12), + UnitsFrequency::GHz => Ok(1e9), + UnitsFrequency::MHz => Ok(1e6), + UnitsFrequency::kHz => Ok(1e3), + UnitsFrequency::hHz => Ok(1e2), + UnitsFrequency::daHz => Ok(1e1), + UnitsFrequency::Hz => Ok(1e0), + UnitsFrequency::dHz => Ok(1e-1), + UnitsFrequency::cHz => Ok(1e-2), + UnitsFrequency::mHz => Ok(1e-3), + UnitsFrequency::uHz => Ok(1e-6), + UnitsFrequency::nHz => Ok(1e-9), + UnitsFrequency::pHz => Ok(1e-12), + UnitsFrequency::fHz => Ok(1e-15), + UnitsFrequency::aHz => Ok(1e-18), + UnitsFrequency::zHz => Ok(1e-21), + UnitsFrequency::yHz => Ok(1e-24), + } + } +} + +impl Convert for UnitsLength { + fn as_si(&self) -> Result { + match self { + UnitsLength::Ym => Ok(1e24), + UnitsLength::Zm => Ok(1e21), + UnitsLength::Em => Ok(1e18), + UnitsLength::Pm => Ok(1e15), + UnitsLength::Tm => Ok(1e12), + UnitsLength::Gm => Ok(1e9), + UnitsLength::Mm => Ok(1e6), + UnitsLength::km => Ok(1e3), + UnitsLength::hm => Ok(1e2), + UnitsLength::dam => Ok(1e1), + UnitsLength::m => Ok(1e0), + UnitsLength::dm => Ok(1e-1), + UnitsLength::cm => Ok(1e-2), + UnitsLength::mm => Ok(1e-3), + UnitsLength::um => Ok(1e-6), + UnitsLength::nm => Ok(1e-9), + UnitsLength::pm => Ok(1e-12), + UnitsLength::fm => Ok(1e-15), + UnitsLength::am => Ok(1e-18), + UnitsLength::zm => Ok(1e-21), + UnitsLength::ym => Ok(1e-24), + UnitsLength::A => Ok(1e-10), + UnitsLength::Thou => Ok(2.54e-5), + UnitsLength::Li => Ok(5e2), + UnitsLength::In => Ok(2.54e-2), + UnitsLength::Ft => Ok(3.05e-1), + UnitsLength::Yd => Ok(9.14e-1), + UnitsLength::Mi => Ok(1.609344e3), + UnitsLength::Ua => Ok(1.496e11), + UnitsLength::Ly => Ok(9.461e15), + UnitsLength::Pc => Ok(3.086e16), + UnitsLength::Pt => Ok(3.52778e-4), + UnitsLength::Pixel => Err(Error::SizeOfUnknown("pixel".to_string())), + UnitsLength::ReferenceFrame => Err(Error::SizeOfUnknown("reference frame".to_string())), + } + } +} + +impl Convert for UnitsPower { + fn as_si(&self) -> Result { + match self { + UnitsPower::YW => Ok(1e24), + UnitsPower::ZW => Ok(1e21), + UnitsPower::EW => Ok(1e18), + UnitsPower::PW => Ok(1e15), + UnitsPower::TW => Ok(1e12), + UnitsPower::GW => Ok(1e9), + UnitsPower::MW => Ok(1e6), + UnitsPower::kW => Ok(1e3), + UnitsPower::hW => Ok(1e2), + UnitsPower::daW => Ok(1e1), + UnitsPower::W => Ok(1e0), + UnitsPower::dW => Ok(1e-1), + UnitsPower::cW => Ok(1e-2), + UnitsPower::mW => Ok(1e-3), + UnitsPower::uW => Ok(1e-6), + UnitsPower::nW => Ok(1e-9), + UnitsPower::pW => Ok(1e-12), + UnitsPower::fW => Ok(1e-15), + UnitsPower::aW => Ok(1e-18), + UnitsPower::zW => Ok(1e-21), + UnitsPower::yW => Ok(1e-24), + } + } +} + +impl Convert for UnitsPressure { + fn as_si(&self) -> Result { + match self { + UnitsPressure::YPa => Ok(1e24), + UnitsPressure::ZPa => Ok(1e21), + UnitsPressure::EPa => Ok(1e18), + UnitsPressure::PPa => Ok(1e15), + UnitsPressure::TPa => Ok(1e12), + UnitsPressure::GPa => Ok(1e9), + UnitsPressure::MPa => Ok(1e6), + UnitsPressure::kPa => Ok(1e3), + UnitsPressure::hPa => Ok(1e2), + UnitsPressure::daPa => Ok(1e1), + UnitsPressure::Pa => Ok(1e0), + UnitsPressure::dPa => Ok(1e-1), + UnitsPressure::cPa => Ok(1e-2), + UnitsPressure::mPa => Ok(1e-3), + UnitsPressure::uPa => Ok(1e-6), + UnitsPressure::nPa => Ok(1e-9), + UnitsPressure::pPa => Ok(1e-12), + UnitsPressure::fPa => Ok(1e-15), + UnitsPressure::aPa => Ok(1e-18), + UnitsPressure::zPa => Ok(1e-21), + UnitsPressure::yPa => Ok(1e-24), + UnitsPressure::bar => Ok(1e5), + UnitsPressure::Mbar => Ok(1e11), + UnitsPressure::kbar => Ok(1e8), + UnitsPressure::dbar => Ok(1e4), + UnitsPressure::cbar => Ok(1e3), + UnitsPressure::mbar => Ok(1e2), + UnitsPressure::atm => Ok(1.01325e5), + UnitsPressure::psi => Ok(6.89476e3), + UnitsPressure::Torr => Ok(1.33322e3), + UnitsPressure::mTorr => Ok(1.33322), + UnitsPressure::mmHg => Ok(1.33322e2), + } + } +} + +impl Convert for UnitsTemperature { + fn as_si(&self) -> Result { + match self { + UnitsTemperature::C => Err(Error::TemparatureConversion), + UnitsTemperature::F => Err(Error::TemparatureConversion), + UnitsTemperature::K => Ok(1e1), + UnitsTemperature::R => Ok(5f64 / 9f64), + } + } + + fn convert(&self, unit: &Self, value: f64) -> Result { + match (self, unit) { + (UnitsTemperature::F, UnitsTemperature::C) => Ok((value - 32.) * 5. / 9.), + (UnitsTemperature::K, UnitsTemperature::C) => Ok(value - 273.15), + (UnitsTemperature::R, UnitsTemperature::C) => Ok((value * 5. / 9.) - 273.15), + (UnitsTemperature::C, UnitsTemperature::F) => Ok((value * 9. / 5.) + 32.), + (UnitsTemperature::K, UnitsTemperature::F) => Ok((value * 9. / 5.) - 459.67), + (UnitsTemperature::R, UnitsTemperature::F) => Ok(value - 459.67), + (UnitsTemperature::C, UnitsTemperature::K) => Ok(value + 273.15), + (UnitsTemperature::F, UnitsTemperature::K) => Ok((value + 459.67) * 5. / 9.), + (UnitsTemperature::R, UnitsTemperature::K) => Ok(value * 5. / 9.), + (UnitsTemperature::C, UnitsTemperature::R) => Ok((value + 273.15) * 9. / 5.), + (UnitsTemperature::F, UnitsTemperature::R) => Ok(value + 459.67), + (UnitsTemperature::K, UnitsTemperature::R) => Ok(value * 9. / 5.), + _ => Ok(value), + } + } +} + +impl Convert for UnitsTime { + fn as_si(&self) -> Result { + match self { + UnitsTime::Ys => Ok(1e24), + UnitsTime::Zs => Ok(1e21), + UnitsTime::Es => Ok(1e18), + UnitsTime::Ps => Ok(1e15), + UnitsTime::Ts => Ok(1e12), + UnitsTime::Gs => Ok(1e9), + UnitsTime::Ms => Ok(1e6), + UnitsTime::ks => Ok(1e3), + UnitsTime::hs => Ok(1e2), + UnitsTime::das => Ok(1e1), + UnitsTime::s => Ok(1e0), + UnitsTime::ds => Ok(1e-1), + UnitsTime::cs => Ok(1e-2), + UnitsTime::ms => Ok(1e-3), + UnitsTime::us => Ok(1e-6), + UnitsTime::ns => Ok(1e-9), + UnitsTime::ps => Ok(1e-12), + UnitsTime::fs => Ok(1e-15), + UnitsTime::r#as => Ok(1e-18), + UnitsTime::zs => Ok(1e-21), + UnitsTime::ys => Ok(1e-24), + UnitsTime::min => Ok(6e1), + UnitsTime::h => Ok(3.6e2), + UnitsTime::d => Ok(8.64e4), + } + } +} diff --git a/ome-metadata/src/py.rs b/ome-metadata/src/py.rs new file mode 100644 index 0000000..08bf5e0 --- /dev/null +++ b/ome-metadata/src/py.rs @@ -0,0 +1,487 @@ +use crate::error::Error; +use crate::ome::{ExperimentType, MetadataOnly, MicrobeamManipulationType, XmlAnnotationValue}; +use pyo3::prelude::*; +use pyo3::types::PyTuple; + +impl From for PyErr { + fn from(err: crate::error::Error) -> PyErr { + color_eyre::eyre::Report::from(err).into() + } +} + +pub(crate) trait PyDisplay { + fn py_str(&self) -> String; +} + +impl PyDisplay for String { + fn py_str(&self) -> String { + self.clone() + } +} + +impl PyDisplay for bool { + fn py_str(&self) -> String { + self.to_string() + } +} + +impl PyDisplay for i32 { + fn py_str(&self) -> String { + self.to_string() + } +} +impl PyDisplay for i64 { + fn py_str(&self) -> String { + self.to_string() + } +} +impl PyDisplay for f32 { + fn py_str(&self) -> String { + self.to_string() + } +} +impl PyDisplay for f64 { + fn py_str(&self) -> String { + self.to_string() + } +} +impl PyDisplay for Option +where + T: PyDisplay, +{ + fn py_str(&self) -> String { + if let Some(val) = self { + val.py_str() + } else { + "None".to_string() + } + } +} + +impl PyDisplay for Vec +where + T: PyDisplay, +{ + fn py_str(&self) -> String { + format!( + "[{}]", + self.iter() + .map(|x| x.py_str()) + .collect::>() + .join(", ") + ) + } +} +impl PyDisplay for MetadataOnly { + fn py_str(&self) -> String { + "MetadataOnly".into() + } +} +impl<'a, 'py> FromPyObject<'a, 'py> for MetadataOnly { + type Error = Error; + + fn extract(_obj: Borrowed<'a, 'py, PyAny>) -> Result { + Ok(Self {}) + } +} +impl PyDisplay for MicrobeamManipulationType { + fn py_str(&self) -> String { + format!( + "[{}]", + self.0 + .iter() + .map(|i| i.py_str()) + .collect::>() + .join(", ") + ) + } +} +impl<'a, 'py> FromPyObject<'a, 'py> for XmlAnnotationValue { + type Error = Error; + + fn extract(_obj: Borrowed<'a, 'py, PyAny>) -> Result { + Ok(Self {}) + } +} +impl PyDisplay for XmlAnnotationValue { + fn py_str(&self) -> String { + "XmlAnnotationValue".to_string() + } +} +impl PyDisplay for ExperimentType { + fn py_str(&self) -> String { + format!( + "[{}]", + self.0 + .iter() + .map(|i| i.py_str()) + .collect::>() + .join(", ") + ) + } +} + +#[pymethods] +impl MetadataOnly { + fn __getnewargs__<'py>(&self, py: Python<'py>) -> Bound<'py, PyTuple> { + PyTuple::empty(py) + } + fn __repr__(&self) -> String { + "MetadataOnly".into() + } + fn __str__(&self) -> String { + "MetadataOnly".into() + } +} + +#[pyfunction] +fn parse_ome(text: &str) -> PyResult { + Ok(crate::ome::Ome::from_xml(text)?) +} + +#[pyfunction] +fn to_xml(ome: crate::ome::Ome) -> PyResult { + Ok(ome.to_xml()?) +} + +#[pymodule] +#[pyo3(name = "ome_metadata")] +pub mod ome_metadata { + use pyo3::prelude::*; + + #[pymodule_export] + use super::parse_ome; + + #[pymodule_export] + use super::to_xml; + + #[pymodule_export] + use crate::ome::AffineTransform; + + #[pymodule_export] + use crate::ome::Annotation; + + #[pymodule_export] + use crate::ome::AnnotationRef; + + #[pymodule_export] + use crate::ome::Arc; + + #[pymodule_export] + use crate::ome::BinData; + + #[pymodule_export] + use crate::ome::BinaryFile; + + #[pymodule_export] + use crate::ome::BooleanAnnotation; + + #[pymodule_export] + use crate::ome::Channel; + + #[pymodule_export] + use crate::ome::CommentAnnotation; + + #[pymodule_export] + use crate::ome::Dataset; + + #[pymodule_export] + use crate::ome::Detector; + + #[pymodule_export] + use crate::ome::DetectorSettings; + + #[pymodule_export] + use crate::ome::Dichroic; + + #[pymodule_export] + use crate::ome::DoubleAnnotation; + + #[pymodule_export] + use crate::ome::Ellipse; + + #[pymodule_export] + use crate::ome::Experiment; + + #[pymodule_export] + use crate::ome::ExperimentType; + + #[pymodule_export] + use crate::ome::Experimenter; + + #[pymodule_export] + use crate::ome::ExperimenterGroup; + + #[pymodule_export] + use crate::ome::External; + + #[pymodule_export] + use crate::ome::Filament; + + #[pymodule_export] + use crate::ome::FileAnnotation; + + #[pymodule_export] + use crate::ome::Filter; + + #[pymodule_export] + use crate::ome::FilterSet; + + #[pymodule_export] + use crate::ome::Folder; + + #[pymodule_export] + use crate::ome::GenericExcitationSource; + + #[pymodule_export] + use crate::ome::Image; + + #[pymodule_export] + use crate::ome::ImagingEnvironment; + + #[pymodule_export] + use crate::ome::Instrument; + + #[pymodule_export] + use crate::ome::Label; + + #[pymodule_export] + use crate::ome::Laser; + + #[pymodule_export] + use crate::ome::LightEmittingDiode; + + #[pymodule_export] + use crate::ome::LightPath; + + #[pymodule_export] + use crate::ome::LightSourceType; + + #[pymodule_export] + use crate::ome::LightSourceSettings; + + #[pymodule_export] + use crate::ome::Line; + + #[pymodule_export] + use crate::ome::LongAnnotation; + + #[pymodule_export] + use crate::ome::MapType; + + #[pymodule_export] + use crate::ome::MapAnnotation; + + #[pymodule_export] + use crate::ome::MapM; + + #[pymodule_export] + use crate::ome::Mask; + + #[pymodule_export] + use crate::ome::MetadataOnly; + + #[pymodule_export] + use crate::ome::MicrobeamManipulation; + + #[pymodule_export] + use crate::ome::MicrobeamManipulationType; + + #[pymodule_export] + use crate::ome::Microscope; + + #[pymodule_export] + use crate::ome::Ome; + + #[pymodule_export] + use crate::ome::Objective; + + #[pymodule_export] + use crate::ome::ObjectiveSettings; + + #[pymodule_export] + use crate::ome::OmeBinaryOnly; + + #[pymodule_export] + use crate::ome::Pixels; + + #[pymodule_export] + use crate::ome::Plane; + + #[pymodule_export] + use crate::ome::Plate; + + #[pymodule_export] + use crate::ome::PlateAcquisition; + + #[pymodule_export] + use crate::ome::Polygon; + + #[pymodule_export] + use crate::ome::Polyline; + + #[pymodule_export] + use crate::ome::Project; + + #[pymodule_export] + use crate::ome::Roi; + + #[pymodule_export] + use crate::ome::Reagent; + + #[pymodule_export] + use crate::ome::Rectangle; + + #[pymodule_export] + use crate::ome::Rights; + + #[pymodule_export] + use crate::ome::RoiUnion; + + #[pymodule_export] + use crate::ome::Screen; + + #[pymodule_export] + use crate::ome::ShapeType; + + #[pymodule_export] + use crate::ome::StageLabel; + + #[pymodule_export] + use crate::ome::StructuredAnnotations; + + #[pymodule_export] + use crate::ome::TiffData; + + #[pymodule_export] + use crate::ome::TiffDataUuid; + + #[pymodule_export] + use crate::ome::TransmittanceRange; + + #[pymodule_export] + use crate::ome::Well; + + #[pymodule_export] + use crate::ome::WellSample; + + #[pymodule_export] + use crate::ome::XmlAnnotation; + + #[pymodule_export] + use crate::ome::XmlAnnotationValue; + + #[pymodule_export] + use crate::ome::ArcType; + + #[pymodule_export] + use crate::ome::BinDataCompressionType; + + #[pymodule_export] + use crate::ome::BinaryFileContent; + + #[pymodule_export] + use crate::ome::BinningType; + + #[pymodule_export] + use crate::ome::ChannelAcquisitionModeType; + + #[pymodule_export] + use crate::ome::ChannelContrastMethodType; + + #[pymodule_export] + use crate::ome::ChannelIlluminationType; + + #[pymodule_export] + use crate::ome::DetectorType; + + #[pymodule_export] + use crate::ome::ExperimentItemType; + + #[pymodule_export] + use crate::ome::FilamentType; + + #[pymodule_export] + use crate::ome::FilterType; + + #[pymodule_export] + use crate::ome::FontFamilyType; + + #[pymodule_export] + use crate::ome::LaserLaserMediumType; + + #[pymodule_export] + use crate::ome::LaserPulseType; + + #[pymodule_export] + use crate::ome::LaserType; + + #[pymodule_export] + use crate::ome::LightSourceGroup; + + #[pymodule_export] + use crate::ome::MarkerType; + + #[pymodule_export] + use crate::ome::MicrobeamManipulationItemType; + + #[pymodule_export] + use crate::ome::MicroscopeType; + + #[pymodule_export] + use crate::ome::NamingConventionType; + + #[pymodule_export] + use crate::ome::ObjectiveCorrectionType; + + #[pymodule_export] + use crate::ome::ObjectiveImmersionType; + + #[pymodule_export] + use crate::ome::ObjectiveSettingsMediumType; + + #[pymodule_export] + use crate::ome::PixelType; + + #[pymodule_export] + use crate::ome::PixelsDimensionOrderType; + + #[pymodule_export] + use crate::ome::ShapeFillRuleType; + + #[pymodule_export] + use crate::ome::ShapeFontStyleType; + + #[pymodule_export] + use crate::ome::ShapeGroup; + + #[pymodule_export] + use crate::ome::StructuredAnnotationsContent; + + #[pymodule_export] + use crate::ome::UnitsElectricPotential; + + #[pymodule_export] + use crate::ome::UnitsFrequency; + + #[pymodule_export] + use crate::ome::UnitsLength; + + #[pymodule_export] + use crate::ome::UnitsPower; + + #[pymodule_export] + use crate::ome::UnitsPressure; + + #[pymodule_export] + use crate::ome::UnitsTemperature; + + #[pymodule_export] + use crate::ome::UnitsTime; + + #[pymodule_init] + fn init(_: &Bound<'_, PyModule>) -> PyResult<()> { + let _ = color_eyre::install(); + Ok(()) + } +} diff --git a/tests/1xp53-01-AP1.xml b/ome-metadata/tests/1xp53-01-AP1.xml similarity index 100% rename from tests/1xp53-01-AP1.xml rename to ome-metadata/tests/1xp53-01-AP1.xml diff --git a/tests/20230511-p53-4x-CMV-1min-4h-01-Airyscan Processing-01.xml b/ome-metadata/tests/20230511-p53-4x-CMV-1min-4h-01-Airyscan Processing-01.xml similarity index 100% rename from tests/20230511-p53-4x-CMV-1min-4h-01-Airyscan Processing-01.xml rename to ome-metadata/tests/20230511-p53-4x-CMV-1min-4h-01-Airyscan Processing-01.xml diff --git a/tests/4-Pos_001_002.xml b/ome-metadata/tests/4-Pos_001_002.xml similarity index 100% rename from tests/4-Pos_001_002.xml rename to ome-metadata/tests/4-Pos_001_002.xml diff --git a/tests/Experiment-2029.xml b/ome-metadata/tests/Experiment-2029.xml similarity index 100% rename from tests/Experiment-2029.xml rename to ome-metadata/tests/Experiment-2029.xml diff --git a/tests/MK022_cE9_1-01-Airyscan Processing-01-Scene-2-P1.xml b/ome-metadata/tests/MK022_cE9_1-01-Airyscan Processing-01-Scene-2-P1.xml similarity index 100% rename from tests/MK022_cE9_1-01-Airyscan Processing-01-Scene-2-P1.xml rename to ome-metadata/tests/MK022_cE9_1-01-Airyscan Processing-01-Scene-2-P1.xml diff --git a/tests/YTL1841B2-2-1_1hr_DMSO_galinduction_1.xml b/ome-metadata/tests/YTL1841B2-2-1_1hr_DMSO_galinduction_1.xml similarity index 100% rename from tests/YTL1841B2-2-1_1hr_DMSO_galinduction_1.xml rename to ome-metadata/tests/YTL1841B2-2-1_1hr_DMSO_galinduction_1.xml diff --git a/tests/YTL1849A111_2023_05_04__14_46_19_cellnr_1_track.xml b/ome-metadata/tests/YTL1849A111_2023_05_04__14_46_19_cellnr_1_track.xml similarity index 100% rename from tests/YTL1849A111_2023_05_04__14_46_19_cellnr_1_track.xml rename to ome-metadata/tests/YTL1849A111_2023_05_04__14_46_19_cellnr_1_track.xml diff --git a/tests/YTL1849A131_2023_05_04__13_36_36.xml b/ome-metadata/tests/YTL1849A131_2023_05_04__13_36_36.xml similarity index 100% rename from tests/YTL1849A131_2023_05_04__13_36_36.xml rename to ome-metadata/tests/YTL1849A131_2023_05_04__13_36_36.xml diff --git a/tests/YTL378_JF552.xml b/ome-metadata/tests/YTL378_JF552.xml similarity index 100% rename from tests/YTL378_JF552.xml rename to ome-metadata/tests/YTL378_JF552.xml diff --git a/tests/beads_2023_05_04__19_00_22.xml b/ome-metadata/tests/beads_2023_05_04__19_00_22.xml similarity index 100% rename from tests/beads_2023_05_04__19_00_22.xml rename to ome-metadata/tests/beads_2023_05_04__19_00_22.xml diff --git a/tests/multi-channel.ome.xml b/ome-metadata/tests/multi-channel.ome.xml similarity index 100% rename from tests/multi-channel.ome.xml rename to ome-metadata/tests/multi-channel.ome.xml diff --git a/tests/test.xml b/ome-metadata/tests/test.xml similarity index 100% rename from tests/test.xml rename to ome-metadata/tests/test.xml diff --git a/py/ome_metadata/__init__.py b/py/ome_metadata/__init__.py deleted file mode 100644 index cfbb99e..0000000 --- a/py/ome_metadata/__init__.py +++ /dev/null @@ -1,45 +0,0 @@ -from __future__ import annotations - -from collections import UserDict, UserList -from . import ome_metadata_rs as rs # noqa - - -class Ome(UserDict): - @staticmethod - def from_xml(xml: str) -> Ome: - """Create the OME structure from an XML string""" - new = Ome() - new.update(rs.ome(str(xml))) - return new - - def __dir__(self) -> list[str]: - return list(self.keys()) + list(super().__dir__()) - - def __getattr__(self, key: str) -> Ome | OmeList | int | float | str: - try: - new = self.__getitem__(key) - except KeyError: - raise AttributeError(f"'Ome' object has no attribute '{key}'") - if isinstance(new, dict): - return Ome(**new) - elif isinstance(new, list): - return OmeList(new) - else: - return new - - def __getstate__(self) -> dict[str, Any]: - return self.data - - def __setstate__(self, state: dict[str, Any]) -> None: - self.data = state - - -class OmeList(UserList): - def __getitem__(self, item: int) -> Ome | OmeList | int | float | str: - new = super().__getitem__(item) - if isinstance(new, dict): - return Ome(**new) - elif isinstance(new, list): - return OmeList(new) - else: - return new diff --git a/pyproject.toml b/pyproject.toml deleted file mode 100644 index 20d2ce6..0000000 --- a/pyproject.toml +++ /dev/null @@ -1,32 +0,0 @@ -[build-system] -requires = ["maturin>=1.8,<2.0"] -build-backend = "maturin" - -[project] -name = "ome-metadata" -keywords = ["bioformats", "imread", "ome", "metadata"] -requires-python = ">=3.10" -classifiers = [ - "License :: OSI Approved :: MIT License", - "Programming Language :: Rust", - "Programming Language :: Python", - "Programming Language :: Python :: 3", - "Programming Language :: Python :: 3 :: Only", - "Programming Language :: Python :: 3.10", - "Programming Language :: Python :: 3.11", - "Programming Language :: Python :: 3.12", - "Programming Language :: Python :: 3.13", - "Programming Language :: Python :: 3.14", -] -dynamic = ["version", "description", "authors", "license", "readme"] - -[project.urls] -Repository = "https://github.com/wimpomp/ome-metadata" - -[tool.maturin] -python-source = "py" -features = ["pyo3/extension-module", "python"] -module-name = "ome_metadata.ome_metadata_rs" - -[tool.isort] -line_length = 119 diff --git a/src/ome.rs b/src/ome.rs deleted file mode 100644 index c68a29c..0000000 --- a/src/ome.rs +++ /dev/null @@ -1,3022 +0,0 @@ -use crate::error::Error; -use enum_utils::{FromStr, IterVariants}; -#[cfg(feature = "python")] -use pyo3::types::{PyDict, PyInt, PyString}; -#[cfg(feature = "python")] -use pyo3::{Bound, IntoPyObject, PyErr, PyResult, Python}; -use serde::{Deserialize, Serialize}; -use std::cmp::PartialEq; - -#[cfg(feature = "python")] -macro_rules! impl_enum_into_py_object { - ($($t:ty $(,)?)*) => { - $( - impl<'py> IntoPyObject<'py> for $t { - type Target = PyString; - type Output = Bound<'py, Self::Target>; - type Error = PyErr; - - fn into_pyobject(self, py: Python<'py>) -> PyResult { - Ok(format!("{:?}", self).into_pyobject(py)?) - } - } - )* - }; -} - -#[cfg(feature = "python")] -macro_rules! impl_empty_struct_into_py_object { - ($($t:ty $(,)?)*) => { - $( - impl<'py> IntoPyObject<'py> for $t { - type Target = PyInt; - type Output = Bound<'py, Self::Target>; - type Error = PyErr; - - fn into_pyobject(self, py: Python<'py>) -> PyResult { - Ok(0usize.into_pyobject(py)?) - } - } - )* - }; -} - -#[cfg(feature = "python")] -macro_rules! impl_boxed_struct_into_py_object { - ($($t:ty $(,)?)*) => { - $( - impl<'py> IntoPyObject<'py> for Box<$t> { - type Target = PyDict; - type Output = Bound<'py, Self::Target>; - type Error = PyErr; - - fn into_pyobject(self, py: Python<'py>) -> PyResult { - (*self).into_pyobject(py) - } - } - )* - }; -} - -#[cfg(feature = "python")] -impl_enum_into_py_object!( - ArcType, - BinDataCompressionType, - BinningType, - ChannelIlluminationType, - ChannelAcquisitionModeType, - ChannelContrastMethodType, - DetectorType, - ExperimentItemType, - FilamentType, - FilterType, - FontFamilyType, - LaserType, - LaserLaserMediumType, - LaserPulseType, - MarkerType, - MicrobeamManipulationItemType, - MicroscopeType, - NamingConventionType, - ObjectiveCorrectionType, - ObjectiveImmersionType, - ObjectiveSettingsMediumType, - PixelsDimensionOrderType, - PixelType, - ShapeFillRuleType, - ShapeFontStyleType -); - -#[cfg(feature = "python")] -impl_empty_struct_into_py_object!(MetadataOnly, XmlAnnotationValue); -#[cfg(feature = "python")] -impl_boxed_struct_into_py_object!(Channel, Image); - -#[cfg_attr(feature = "python", derive(IntoPyObject))] -#[derive(Clone, Debug, Serialize, Deserialize)] -pub struct AffineTransform { - #[serde(rename = "@A00")] - pub a00: f32, - #[serde(rename = "@A10")] - pub a10: f32, - #[serde(rename = "@A01")] - pub a01: f32, - #[serde(rename = "@A11")] - pub a11: f32, - #[serde(rename = "@A02")] - pub a02: f32, - #[serde(rename = "@A12")] - pub a12: f32, -} -#[cfg_attr(feature = "python", derive(IntoPyObject))] -#[derive(Clone, Debug, Serialize, Deserialize)] -pub struct Annotation { - #[serde(rename = "@ID")] - pub id: String, - #[serde(default, rename = "@Namespace")] - pub namespace: Option, - #[serde(default, rename = "@Annotator")] - pub annotator: Option, - #[serde(default, rename = "Description")] - pub description: Option, - #[serde(default, rename = "AnnotationRef")] - pub annotation_ref: Vec, -} -#[cfg_attr(feature = "python", derive(IntoPyObject))] -#[derive(Clone, Debug, Serialize, Deserialize)] -pub struct AnnotationRef { - #[serde(rename = "@ID")] - pub id: String, -} -#[cfg_attr(feature = "python", derive(IntoPyObject))] -#[derive(Clone, Debug, Serialize, Deserialize)] -pub struct Arc { - #[serde(default, rename = "@Manufacturer")] - pub manufacturer: Option, - #[serde(default, rename = "@Model")] - pub model: Option, - #[serde(default, rename = "@SerialNumber")] - pub serial_number: Option, - #[serde(default, rename = "@LotNumber")] - pub lot_number: Option, - #[serde(rename = "@ID")] - pub id: String, - #[serde(default, rename = "@Power")] - pub power: Option, - #[serde(default = "Arc::default_power_unit", rename = "@PowerUnit")] - pub power_unit: UnitsPower, - #[serde(default, rename = "@Type")] - pub r#type: Option, - #[serde(default, rename = "AnnotationRef")] - pub annotation_ref: Vec, -} -impl Arc { - pub fn default_power_unit() -> UnitsPower { - UnitsPower::W - } -} -#[derive(Clone, Debug, Serialize, Deserialize)] -pub enum ArcType { - #[serde(rename = "Hg")] - Hg, - #[serde(rename = "Xe")] - Xe, - #[serde(rename = "HgXe")] - HgXe, - #[serde(rename = "Other")] - Other, -} -#[cfg_attr(feature = "python", derive(IntoPyObject))] -#[derive(Clone, Debug, Serialize, Deserialize)] -pub struct BinData { - #[serde(default = "BinData::default_compression", rename = "@Compression")] - pub compression: BinDataCompressionType, - #[serde(rename = "@BigEndian")] - pub big_endian: bool, - #[serde(rename = "@Length")] - pub length: i64, - #[serde(rename = "$text")] - pub content: String, -} -impl BinData { - pub fn default_compression() -> BinDataCompressionType { - BinDataCompressionType::None - } -} -#[derive(Clone, Debug, Serialize, Deserialize)] -pub enum BinDataCompressionType { - #[serde(rename = "zlib")] - Zlib, - #[serde(rename = "bzip2")] - Bzip2, - #[serde(rename = "none")] - None, -} -#[cfg_attr(feature = "python", derive(IntoPyObject))] -#[derive(Clone, Debug, Serialize, Deserialize)] -pub struct BinaryFile { - #[serde(rename = "@FileName")] - pub file_name: String, - #[serde(rename = "@Size")] - pub size: i64, - #[serde(default, rename = "@MIMEType")] - pub mime_type: Option, - #[serde(rename = "$value")] - pub content: BinaryFileContent, -} -#[cfg_attr(feature = "python", derive(IntoPyObject))] -#[derive(Clone, Debug, Serialize, Deserialize)] -pub enum BinaryFileContent { - #[serde(rename = "External")] - External(External), - #[serde(rename = "BinData")] - BinData(BinData), -} -#[derive(Clone, Debug, Serialize, Deserialize)] -pub enum BinningType { - #[serde(rename = "1x1")] - _1X1, - #[serde(rename = "2x2")] - _2X2, - #[serde(rename = "4x4")] - _4X4, - #[serde(rename = "8x8")] - _8X8, - #[serde(rename = "Other")] - Other, -} -#[cfg_attr(feature = "python", derive(IntoPyObject))] -#[derive(Clone, Debug, Serialize, Deserialize)] -pub struct BooleanAnnotation { - #[serde(rename = "@ID")] - pub id: String, - #[serde(default, rename = "@Namespace")] - pub namespace: Option, - #[serde(default, rename = "@Annotator")] - pub annotator: Option, - #[serde(default, rename = "Description")] - pub description: Option, - #[serde(default, rename = "AnnotationRef")] - pub annotation_ref: Vec, - #[serde(rename = "Value")] - pub value: bool, -} -#[cfg_attr(feature = "python", derive(IntoPyObject))] -#[derive(Clone, Debug, Serialize, Deserialize)] -pub struct Channel { - #[serde(rename = "@ID")] - pub id: String, - #[serde(default, rename = "@Name")] - pub name: Option, - #[serde(default, rename = "@SamplesPerPixel")] - pub samples_per_pixel: Option, - #[serde(default, rename = "@IlluminationType")] - pub illumination_type: Option, - #[serde(default, rename = "@PinholeSize")] - pub pinhole_size: Option, - #[serde( - default = "Channel::default_pinhole_size_unit", - rename = "@PinholeSizeUnit" - )] - pub pinhole_size_unit: UnitsLength, - #[serde(default, rename = "@AcquisitionMode")] - pub acquisition_mode: Option, - #[serde(default, rename = "@ContrastMethod")] - pub contrast_method: Option, - #[serde(default, rename = "@ExcitationWavelength")] - pub excitation_wavelength: Option, - #[serde( - default = "Channel::default_excitation_wavelength_unit", - rename = "@ExcitationWavelengthUnit" - )] - pub excitation_wavelength_unit: UnitsLength, - #[serde(default, rename = "@EmissionWavelength")] - pub emission_wavelength: Option, - #[serde( - default = "Channel::default_emission_wavelength_unit", - rename = "@EmissionWavelengthUnit" - )] - pub emission_wavelength_unit: UnitsLength, - #[serde(default, rename = "@Fluor")] - pub fluor: Option, - #[serde(default, rename = "@NDFilter")] - pub nd_filter: Option, - #[serde(default, rename = "@PockelCellSetting")] - pub pockel_cell_setting: Option, - #[serde(default = "Channel::default_color", rename = "@Color")] - pub color: i32, - #[serde(default, rename = "LightSourceSettings")] - pub light_source_settings: Option, - #[serde(default, rename = "DetectorSettings")] - pub detector_settings: Option, - #[serde(default, rename = "FilterSetRef")] - pub filter_set_ref: Option, - #[serde(default, rename = "AnnotationRef")] - pub annotation_ref: Vec, - #[serde(default, rename = "LightPath")] - pub light_path: Option, -} -impl Channel { - pub fn default_pinhole_size_unit() -> UnitsLength { - UnitsLength::um - } - pub fn default_color() -> i32 { - 0 - } - pub fn default_excitation_wavelength_unit() -> UnitsLength { - UnitsLength::nm - } - pub fn default_emission_wavelength_unit() -> UnitsLength { - UnitsLength::nm - } -} -#[derive(Clone, Debug, Serialize, Deserialize)] -pub enum ChannelAcquisitionModeType { - #[serde(rename = "WideField")] - WideField, - #[serde(rename = "LaserScanningConfocalMicroscopy")] - LaserScanningConfocalMicroscopy, - #[serde(rename = "SpinningDiskConfocal")] - SpinningDiskConfocal, - #[serde(rename = "SlitScanConfocal")] - SlitScanConfocal, - #[serde(rename = "MultiPhotonMicroscopy")] - MultiPhotonMicroscopy, - #[serde(rename = "StructuredIllumination")] - StructuredIllumination, - #[serde(rename = "SingleMoleculeImaging")] - SingleMoleculeImaging, - #[serde(rename = "TotalInternalReflection")] - TotalInternalReflection, - #[serde(rename = "FluorescenceLifetime")] - FluorescenceLifetime, - #[serde(rename = "SpectralImaging")] - SpectralImaging, - #[serde(rename = "FluorescenceCorrelationSpectroscopy")] - FluorescenceCorrelationSpectroscopy, - #[serde(rename = "NearFieldScanningOpticalMicroscopy")] - NearFieldScanningOpticalMicroscopy, - #[serde(rename = "SecondHarmonicGenerationImaging")] - SecondHarmonicGenerationImaging, - #[serde(rename = "PALM")] - Palm, - #[serde(rename = "STORM")] - Storm, - #[serde(rename = "STED")] - Sted, - #[serde(rename = "TIRF")] - Tirf, - #[serde(rename = "FSM")] - Fsm, - #[serde(rename = "LCM")] - Lcm, - #[serde(rename = "Other")] - Other, - #[serde(rename = "BrightField")] - BrightField, - #[serde(rename = "SweptFieldConfocal")] - SweptFieldConfocal, - #[serde(rename = "SPIM")] - Spim, -} -#[derive(Clone, Debug, Serialize, Deserialize)] -pub enum ChannelContrastMethodType { - #[serde(rename = "Brightfield")] - Brightfield, - #[serde(rename = "Phase")] - Phase, - #[serde(rename = "DIC")] - Dic, - #[serde(rename = "HoffmanModulation")] - HoffmanModulation, - #[serde(rename = "ObliqueIllumination")] - ObliqueIllumination, - #[serde(rename = "PolarizedLight")] - PolarizedLight, - #[serde(rename = "Darkfield")] - Darkfield, - #[serde(rename = "Fluorescence")] - Fluorescence, - #[serde(rename = "Other")] - Other, -} -#[derive(Clone, Debug, Serialize, Deserialize)] -pub enum ChannelIlluminationType { - #[serde(rename = "Transmitted")] - Transmitted, - #[serde(rename = "Epifluorescence")] - Epifluorescence, - #[serde(rename = "Oblique")] - Oblique, - #[serde(rename = "NonLinear")] - NonLinear, - #[serde(rename = "Other")] - Other, -} -#[cfg_attr(feature = "python", derive(IntoPyObject))] -#[derive(Clone, Debug, Serialize, Deserialize)] -pub struct CommentAnnotation { - #[serde(rename = "@ID")] - pub id: String, - #[serde(default, rename = "@Namespace")] - pub namespace: Option, - #[serde(default, rename = "@Annotator")] - pub annotator: Option, - #[serde(default, rename = "Description")] - pub description: Option, - #[serde(default, rename = "AnnotationRef")] - pub annotation_ref: Vec, - #[serde(rename = "Value")] - pub value: String, -} -#[cfg_attr(feature = "python", derive(IntoPyObject))] -#[derive(Clone, Debug, Serialize, Deserialize)] -pub struct Dataset { - #[serde(default, rename = "@Name")] - pub name: Option, - #[serde(rename = "@ID")] - pub id: String, - #[serde(default, rename = "Description")] - pub description: Option, - #[serde(default, rename = "ExperimenterRef")] - pub experimenter_ref: Option, - #[serde(default, rename = "ExperimenterGroupRef")] - pub experimenter_group_ref: Option, - #[serde(default, rename = "ImageRef")] - pub image_ref: Vec, - #[serde(default, rename = "AnnotationRef")] - pub annotation_ref: Vec, -} -#[cfg_attr(feature = "python", derive(IntoPyObject))] -#[derive(Clone, Debug, Serialize, Deserialize)] -pub struct Detector { - #[serde(default, rename = "@Manufacturer")] - pub manufacturer: Option, - #[serde(default, rename = "@Model")] - pub model: Option, - #[serde(default, rename = "@SerialNumber")] - pub serial_number: Option, - #[serde(default, rename = "@LotNumber")] - pub lot_number: Option, - #[serde(default, rename = "@Gain")] - pub gain: Option, - #[serde(default, rename = "@Voltage")] - pub voltage: Option, - #[serde(default = "Detector::default_voltage_unit", rename = "@VoltageUnit")] - pub voltage_unit: UnitsElectricPotential, - #[serde(default, rename = "@Offset")] - pub offset: Option, - #[serde(default, rename = "@Zoom")] - pub zoom: Option, - #[serde(default, rename = "@AmplificationGain")] - pub amplification_gain: Option, - #[serde(rename = "@ID")] - pub id: String, - #[serde(default, rename = "@Type")] - pub r#type: Option, - #[serde(default, rename = "AnnotationRef")] - pub annotation_ref: Vec, -} -impl Detector { - pub fn default_voltage_unit() -> UnitsElectricPotential { - UnitsElectricPotential::V - } -} -#[cfg_attr(feature = "python", derive(IntoPyObject))] -#[derive(Clone, Debug, Serialize, Deserialize)] -pub struct DetectorSettings { - #[serde(rename = "@ID")] - pub id: String, - #[serde(default, rename = "@Offset")] - pub offset: Option, - #[serde(default, rename = "@Gain")] - pub gain: Option, - #[serde(default, rename = "@Voltage")] - pub voltage: Option, - #[serde( - default = "DetectorSettings::default_voltage_unit", - rename = "@VoltageUnit" - )] - pub voltage_unit: UnitsElectricPotential, - #[serde(default, rename = "@Zoom")] - pub zoom: Option, - #[serde(default, rename = "@ReadOutRate")] - pub read_out_rate: Option, - #[serde( - default = "DetectorSettings::default_read_out_rate_unit", - rename = "@ReadOutRateUnit" - )] - pub read_out_rate_unit: UnitsFrequency, - #[serde(default, rename = "@Binning")] - pub binning: Option, - #[serde(default, rename = "@Integration")] - pub integration: Option, -} -impl DetectorSettings { - pub fn default_voltage_unit() -> UnitsElectricPotential { - UnitsElectricPotential::V - } - pub fn default_read_out_rate_unit() -> UnitsFrequency { - UnitsFrequency::Hz - } -} -#[derive(Clone, Debug, Serialize, Deserialize)] -pub enum DetectorType { - #[serde(rename = "CCD")] - Ccd, - #[serde(rename = "IntensifiedCCD")] - IntensifiedCcd, - #[serde(rename = "AnalogVideo")] - AnalogVideo, - #[serde(rename = "PMT")] - Pmt, - #[serde(rename = "Photodiode")] - Photodiode, - #[serde(rename = "Spectroscopy")] - Spectroscopy, - #[serde(rename = "LifetimeImaging")] - LifetimeImaging, - #[serde(rename = "CorrelationSpectroscopy")] - CorrelationSpectroscopy, - #[serde(rename = "FTIR")] - Ftir, - #[serde(rename = "EMCCD")] - Emccd, - #[serde(rename = "APD")] - Apd, - #[serde(rename = "CMOS")] - Cmos, - #[serde(rename = "EBCCD")] - Ebccd, - #[serde(rename = "Other")] - Other, -} -#[cfg_attr(feature = "python", derive(IntoPyObject))] -#[derive(Clone, Debug, Serialize, Deserialize)] -pub struct Dichroic { - #[serde(default, rename = "@Manufacturer")] - pub manufacturer: Option, - #[serde(default, rename = "@Model")] - pub model: Option, - #[serde(default, rename = "@SerialNumber")] - pub serial_number: Option, - #[serde(default, rename = "@LotNumber")] - pub lot_number: Option, - #[serde(rename = "@ID")] - pub id: String, - #[serde(default, rename = "AnnotationRef")] - pub annotation_ref: Vec, -} -#[cfg_attr(feature = "python", derive(IntoPyObject))] -#[derive(Clone, Debug, Serialize, Deserialize)] -pub struct DoubleAnnotation { - #[serde(rename = "@ID")] - pub id: String, - #[serde(default, rename = "@Namespace")] - pub namespace: Option, - #[serde(default, rename = "@Annotator")] - pub annotator: Option, - #[serde(default, rename = "Description")] - pub description: Option, - #[serde(default, rename = "AnnotationRef")] - pub annotation_ref: Vec, - #[serde(rename = "Value")] - pub value: f64, -} -#[cfg_attr(feature = "python", derive(IntoPyObject))] -#[derive(Clone, Debug, Serialize, Deserialize)] -pub struct Ellipse { - #[serde(default, rename = "@FillColor")] - pub fill_color: Option, - #[serde(default, rename = "@FillRule")] - pub fill_rule: Option, - #[serde(default, rename = "@StrokeColor")] - pub stroke_color: Option, - #[serde(default, rename = "@StrokeWidth")] - pub stroke_width: Option, - #[serde( - default = "Ellipse::default_stroke_width_unit", - rename = "@StrokeWidthUnit" - )] - pub stroke_width_unit: UnitsLength, - #[serde(default, rename = "@StrokeDashArray")] - pub stroke_dash_array: Option, - #[serde(default, rename = "@Text")] - pub text: Option, - #[serde(default, rename = "@FontFamily")] - pub font_family: Option, - #[serde(default, rename = "@FontSize")] - pub font_size: Option, - #[serde(default = "Ellipse::default_font_size_unit", rename = "@FontSizeUnit")] - pub font_size_unit: UnitsLength, - #[serde(default, rename = "@FontStyle")] - pub font_style: Option, - #[serde(default, rename = "@Locked")] - pub locked: Option, - #[serde(rename = "@ID")] - pub id: String, - #[serde(default, rename = "@TheZ")] - pub the_z: Option, - #[serde(default, rename = "@TheT")] - pub the_t: Option, - #[serde(default, rename = "@TheC")] - pub the_c: Option, - #[serde(rename = "@X")] - pub x: f32, - #[serde(rename = "@Y")] - pub y: f32, - #[serde(rename = "@RadiusX")] - pub radius_x: f32, - #[serde(rename = "@RadiusY")] - pub radius_y: f32, - #[serde(default, rename = "Transform")] - pub transform: Option, - #[serde(default, rename = "AnnotationRef")] - pub annotation_ref: Vec, -} -impl Ellipse { - pub fn default_stroke_width_unit() -> UnitsLength { - UnitsLength::Pixel - } - pub fn default_font_size_unit() -> UnitsLength { - UnitsLength::Pixel - } -} -#[cfg_attr(feature = "python", derive(IntoPyObject))] -#[derive(Clone, Debug, Serialize, Deserialize)] -pub struct Experiment { - #[serde(default, rename = "@Type")] - pub r#type: Option, - #[serde(rename = "@ID")] - pub id: String, - #[serde(default, rename = "Description")] - pub description: Option, - #[serde(default, rename = "ExperimenterRef")] - pub experimenter_ref: Option, - #[serde(default, rename = "MicrobeamManipulation")] - pub microbeam_manipulation: Vec, -} -#[derive(Clone, Debug, Serialize, Deserialize)] -pub enum ExperimentItemType { - #[serde(rename = "FP")] - Fp, - #[serde(rename = "FRET")] - Fret, - #[serde(rename = "TimeLapse")] - TimeLapse, - #[serde(rename = "FourDPlus")] - FourDPlus, - #[serde(rename = "Screen")] - Screen, - #[serde(rename = "Immunocytochemistry")] - Immunocytochemistry, - #[serde(rename = "Immunofluorescence")] - Immunofluorescence, - #[serde(rename = "FISH")] - Fish, - #[serde(rename = "Electrophysiology")] - Electrophysiology, - #[serde(rename = "IonImaging")] - IonImaging, - #[serde(rename = "Colocalization")] - Colocalization, - #[serde(rename = "PGIDocumentation")] - PgiDocumentation, - #[serde(rename = "FluorescenceLifetime")] - FluorescenceLifetime, - #[serde(rename = "SpectralImaging")] - SpectralImaging, - #[serde(rename = "Photobleaching")] - Photobleaching, - #[serde(rename = "SPIM")] - Spim, - #[serde(rename = "Other")] - Other, -} -#[cfg_attr(feature = "python", derive(IntoPyObject))] -#[derive(Clone, Debug, Serialize, Deserialize, Default)] -pub struct ExperimentType(pub Vec); -#[cfg_attr(feature = "python", derive(IntoPyObject))] -#[derive(Clone, Debug, Serialize, Deserialize)] -pub struct Experimenter { - #[serde(rename = "@ID")] - pub id: String, - #[serde(default, rename = "@FirstName")] - pub first_name: Option, - #[serde(default, rename = "@MiddleName")] - pub middle_name: Option, - #[serde(default, rename = "@LastName")] - pub last_name: Option, - #[serde(default, rename = "@Email")] - pub email: Option, - #[serde(default, rename = "@Institution")] - pub institution: Option, - #[serde(default, rename = "@UserName")] - pub user_name: Option, - #[serde(default, rename = "AnnotationRef")] - pub annotation_ref: Vec, -} -#[cfg_attr(feature = "python", derive(IntoPyObject))] -#[derive(Clone, Debug, Serialize, Deserialize)] -pub struct ExperimenterGroup { - #[serde(default, rename = "@Name")] - pub name: Option, - #[serde(rename = "@ID")] - pub id: String, - #[serde(default, rename = "Description")] - pub description: Option, - #[serde(default, rename = "ExperimenterRef")] - pub experimenter_ref: Vec, - #[serde(default, rename = "Leader")] - pub leader: Vec, - #[serde(default, rename = "AnnotationRef")] - pub annotation_ref: Vec, -} -#[cfg_attr(feature = "python", derive(IntoPyObject))] -#[derive(Clone, Debug, Serialize, Deserialize)] -pub struct External { - #[serde(rename = "@href")] - pub href: String, - #[serde(rename = "@SHA1")] - pub sha_1: String, - #[serde(default = "External::default_compression", rename = "@Compression")] - pub compression: BinDataCompressionType, -} -impl External { - pub fn default_compression() -> BinDataCompressionType { - BinDataCompressionType::None - } -} -#[cfg_attr(feature = "python", derive(IntoPyObject))] -#[derive(Clone, Debug, Serialize, Deserialize)] -pub struct Filament { - #[serde(default, rename = "@Manufacturer")] - pub manufacturer: Option, - #[serde(default, rename = "@Model")] - pub model: Option, - #[serde(default, rename = "@SerialNumber")] - pub serial_number: Option, - #[serde(default, rename = "@LotNumber")] - pub lot_number: Option, - #[serde(rename = "@ID")] - pub id: String, - #[serde(default, rename = "@Power")] - pub power: Option, - #[serde(default = "Filament::default_power_unit", rename = "@PowerUnit")] - pub power_unit: UnitsPower, - #[serde(default, rename = "@Type")] - pub r#type: Option, - #[serde(default, rename = "AnnotationRef")] - pub annotation_ref: Vec, -} -impl Filament { - pub fn default_power_unit() -> UnitsPower { - UnitsPower::W - } -} -#[derive(Clone, Debug, Serialize, Deserialize)] -pub enum FilamentType { - #[serde(rename = "Incandescent")] - Incandescent, - #[serde(rename = "Halogen")] - Halogen, - #[serde(rename = "Other")] - Other, -} -#[cfg_attr(feature = "python", derive(IntoPyObject))] -#[derive(Clone, Debug, Serialize, Deserialize)] -pub struct FileAnnotation { - #[serde(rename = "@ID")] - pub id: String, - #[serde(default, rename = "@Namespace")] - pub namespace: Option, - #[serde(default, rename = "@Annotator")] - pub annotator: Option, - #[serde(default, rename = "Description")] - pub description: Option, - #[serde(default, rename = "AnnotationRef")] - pub annotation_ref: Vec, - #[serde(rename = "BinaryFile")] - pub binary_file: BinaryFile, -} -#[cfg_attr(feature = "python", derive(IntoPyObject))] -#[derive(Clone, Debug, Serialize, Deserialize)] -pub struct Filter { - #[serde(default, rename = "@Manufacturer")] - pub manufacturer: Option, - #[serde(default, rename = "@Model")] - pub model: Option, - #[serde(default, rename = "@SerialNumber")] - pub serial_number: Option, - #[serde(default, rename = "@LotNumber")] - pub lot_number: Option, - #[serde(default, rename = "@Type")] - pub r#type: Option, - #[serde(default, rename = "@FilterWheel")] - pub filter_wheel: Option, - #[serde(rename = "@ID")] - pub id: String, - #[serde(default, rename = "TransmittanceRange")] - pub transmittance_range: Option, - #[serde(default, rename = "AnnotationRef")] - pub annotation_ref: Vec, -} -#[cfg_attr(feature = "python", derive(IntoPyObject))] -#[derive(Clone, Debug, Serialize, Deserialize)] -pub struct FilterSet { - #[serde(default, rename = "@Manufacturer")] - pub manufacturer: Option, - #[serde(default, rename = "@Model")] - pub model: Option, - #[serde(default, rename = "@SerialNumber")] - pub serial_number: Option, - #[serde(default, rename = "@LotNumber")] - pub lot_number: Option, - #[serde(rename = "@ID")] - pub id: String, - #[serde(default, rename = "ExcitationFilterRef")] - pub excitation_filter_ref: Vec, - #[serde(default, rename = "DichroicRef")] - pub dichroic_ref: Option, - #[serde(default, rename = "EmissionFilterRef")] - pub emission_filter_ref: Vec, -} -#[derive(Clone, Debug, Serialize, Deserialize)] -pub enum FilterType { - #[serde(rename = "Dichroic")] - Dichroic, - #[serde(rename = "LongPass")] - LongPass, - #[serde(rename = "ShortPass")] - ShortPass, - #[serde(rename = "BandPass")] - BandPass, - #[serde(rename = "MultiPass")] - MultiPass, - #[serde(rename = "NeutralDensity")] - NeutralDensity, - #[serde(rename = "Tuneable")] - Tuneable, - #[serde(rename = "Other")] - Other, -} -#[cfg_attr(feature = "python", derive(IntoPyObject))] -#[derive(Clone, Debug, Serialize, Deserialize)] -pub struct Folder { - #[serde(rename = "@ID")] - pub id: String, - #[serde(default, rename = "@Name")] - pub name: Option, - #[serde(default, rename = "Description")] - pub description: Option, - #[serde(default, rename = "FolderRef")] - pub folder_ref: Vec, - #[serde(default, rename = "ImageRef")] - pub image_ref: Vec, - #[serde(default, rename = "ROIRef")] - pub roi_ref: Vec, - #[serde(default, rename = "AnnotationRef")] - pub annotation_ref: Vec, -} -#[derive(Clone, Debug, Serialize, Deserialize)] -pub enum FontFamilyType { - #[serde(rename = "serif")] - Serif, - #[serde(rename = "sans-serif")] - SansSerif, - #[serde(rename = "cursive")] - Cursive, - #[serde(rename = "fantasy")] - Fantasy, - #[serde(rename = "monospace")] - Monospace, -} -#[cfg_attr(feature = "python", derive(IntoPyObject))] -#[derive(Clone, Debug, Serialize, Deserialize)] -pub struct GenericExcitationSource { - #[serde(default, rename = "@Manufacturer")] - pub manufacturer: Option, - #[serde(default, rename = "@Model")] - pub model: Option, - #[serde(default, rename = "@SerialNumber")] - pub serial_number: Option, - #[serde(default, rename = "@LotNumber")] - pub lot_number: Option, - #[serde(rename = "@ID")] - pub id: String, - #[serde(default, rename = "@Power")] - pub power: Option, - #[serde( - default = "GenericExcitationSource::default_power_unit", - rename = "@PowerUnit" - )] - pub power_unit: UnitsPower, - #[serde(default, rename = "AnnotationRef")] - pub annotation_ref: Vec, - #[serde(default, rename = "Map")] - pub map: Option, -} -impl GenericExcitationSource { - pub fn default_power_unit() -> UnitsPower { - UnitsPower::W - } -} -#[cfg_attr(feature = "python", derive(IntoPyObject))] -#[derive(Clone, Debug, Serialize, Deserialize)] -pub struct Image { - #[serde(rename = "@ID")] - pub id: String, - #[serde(default, rename = "@Name")] - pub name: Option, - #[serde(default, rename = "AcquisitionDate")] - pub acquisition_date: Option, - #[serde(default, rename = "ExperimenterRef")] - pub experimenter_ref: Option, - #[serde(default, rename = "Description")] - pub description: Option, - #[serde(default, rename = "ExperimentRef")] - pub experiment_ref: Option, - #[serde(default, rename = "ExperimenterGroupRef")] - pub experimenter_group_ref: Option, - #[serde(default, rename = "InstrumentRef")] - pub instrument_ref: Option, - #[serde(default, rename = "ObjectiveSettings")] - pub objective_settings: Option, - #[serde(default, rename = "ImagingEnvironment")] - pub imaging_environment: Option, - #[serde(default, rename = "StageLabel")] - pub stage_label: Option, - #[serde(rename = "Pixels")] - pub pixels: Pixels, - #[serde(default, rename = "ROIRef")] - pub roi_ref: Vec, - #[serde(default, rename = "MicrobeamManipulationRef")] - pub microbeam_manipulation_ref: Vec, - #[serde(default, rename = "AnnotationRef")] - pub annotation_ref: Vec, -} -#[cfg_attr(feature = "python", derive(IntoPyObject))] -#[derive(Clone, Debug, Serialize, Deserialize)] -pub struct ImagingEnvironment { - #[serde(default, rename = "@Temperature")] - pub temperature: Option, - #[serde( - default = "ImagingEnvironment::default_temperature_unit", - rename = "@TemperatureUnit" - )] - pub temperature_unit: UnitsTemperature, - #[serde(default, rename = "@AirPressure")] - pub air_pressure: Option, - #[serde( - default = "ImagingEnvironment::default_air_pressure_unit", - rename = "@AirPressureUnit" - )] - pub air_pressure_unit: UnitsPressure, - #[serde(default, rename = "@Humidity")] - pub humidity: Option, - #[serde(default, rename = "@CO2Percent")] - pub co_2_percent: Option, - #[serde(default, rename = "Map")] - pub map: Option, -} -impl ImagingEnvironment { - pub fn default_temperature_unit() -> UnitsTemperature { - UnitsTemperature::C - } - pub fn default_air_pressure_unit() -> UnitsPressure { - UnitsPressure::atm - } -} -#[cfg_attr(feature = "python", derive(IntoPyObject))] -#[derive(Clone, Debug, Serialize, Deserialize)] -pub struct Instrument { - #[serde(rename = "@ID")] - pub id: String, - #[serde(default, rename = "Microscope")] - pub microscope: Option, - #[serde(default, rename = "LightSourceGroup")] - pub light_source_group: Vec, - #[serde(default, rename = "Detector")] - pub detector: Vec, - #[serde(default, rename = "Objective")] - pub objective: Vec, - #[serde(default, rename = "FilterSet")] - pub filter_set: Vec, - #[serde(default, rename = "Filter")] - pub filter: Vec, - #[serde(default, rename = "Dichroic")] - pub dichroic: Vec, - #[serde(default, rename = "AnnotationRef")] - pub annotation_ref: Vec, -} -#[cfg_attr(feature = "python", derive(IntoPyObject))] -#[derive(Clone, Debug, Serialize, Deserialize)] -pub struct Label { - #[serde(default, rename = "@FillColor")] - pub fill_color: Option, - #[serde(default, rename = "@FillRule")] - pub fill_rule: Option, - #[serde(default, rename = "@StrokeColor")] - pub stroke_color: Option, - #[serde(default, rename = "@StrokeWidth")] - pub stroke_width: Option, - #[serde( - default = "Label::default_stroke_width_unit", - rename = "@StrokeWidthUnit" - )] - pub stroke_width_unit: UnitsLength, - #[serde(default, rename = "@StrokeDashArray")] - pub stroke_dash_array: Option, - #[serde(default, rename = "@Text")] - pub text: Option, - #[serde(default, rename = "@FontFamily")] - pub font_family: Option, - #[serde(default, rename = "@FontSize")] - pub font_size: Option, - #[serde(default = "Label::default_font_size_unit", rename = "@FontSizeUnit")] - pub font_size_unit: UnitsLength, - #[serde(default, rename = "@FontStyle")] - pub font_style: Option, - #[serde(default, rename = "@Locked")] - pub locked: Option, - #[serde(rename = "@ID")] - pub id: String, - #[serde(default, rename = "@TheZ")] - pub the_z: Option, - #[serde(default, rename = "@TheT")] - pub the_t: Option, - #[serde(default, rename = "@TheC")] - pub the_c: Option, - #[serde(rename = "@X")] - pub x: f32, - #[serde(rename = "@Y")] - pub y: f32, - #[serde(default, rename = "Transform")] - pub transform: Option, - #[serde(default, rename = "AnnotationRef")] - pub annotation_ref: Vec, -} -impl Label { - pub fn default_stroke_width_unit() -> UnitsLength { - UnitsLength::Pixel - } - pub fn default_font_size_unit() -> UnitsLength { - UnitsLength::Pixel - } -} -#[cfg_attr(feature = "python", derive(IntoPyObject))] -#[derive(Clone, Debug, Serialize, Deserialize)] -pub struct Laser { - #[serde(default, rename = "@Manufacturer")] - pub manufacturer: Option, - #[serde(default, rename = "@Model")] - pub model: Option, - #[serde(default, rename = "@SerialNumber")] - pub serial_number: Option, - #[serde(default, rename = "@LotNumber")] - pub lot_number: Option, - #[serde(rename = "@ID")] - pub id: String, - #[serde(default, rename = "@Power")] - pub power: Option, - #[serde(default = "Laser::default_power_unit", rename = "@PowerUnit")] - pub power_unit: UnitsPower, - #[serde(default, rename = "@Type")] - pub r#type: Option, - #[serde(default, rename = "@LaserMedium")] - pub laser_medium: Option, - #[serde(default, rename = "@Wavelength")] - pub wavelength: Option, - #[serde(default = "Laser::default_wavelength_unit", rename = "@WavelengthUnit")] - pub wavelength_unit: UnitsLength, - #[serde(default, rename = "@FrequencyMultiplication")] - pub frequency_multiplication: Option, - #[serde(default, rename = "@Tuneable")] - pub tuneable: Option, - #[serde(default, rename = "@Pulse")] - pub pulse: Option, - #[serde(default, rename = "@PockelCell")] - pub pockel_cell: Option, - #[serde(default, rename = "@RepetitionRate")] - pub repetition_rate: Option, - #[serde( - default = "Laser::default_repetition_rate_unit", - rename = "@RepetitionRateUnit" - )] - pub repetition_rate_unit: UnitsFrequency, - #[serde(default, rename = "AnnotationRef")] - pub annotation_ref: Vec, - #[serde(default, rename = "Pump")] - pub pump: Option, -} -impl Laser { - pub fn default_power_unit() -> UnitsPower { - UnitsPower::mW - } - pub fn default_wavelength_unit() -> UnitsLength { - UnitsLength::nm - } - pub fn default_repetition_rate_unit() -> UnitsFrequency { - UnitsFrequency::Hz - } -} -#[derive(Clone, Debug, Serialize, Deserialize)] -pub enum LaserLaserMediumType { - #[serde(rename = "Cu")] - Cu, - #[serde(rename = "Ag")] - Ag, - #[serde(rename = "ArFl")] - ArFl, - #[serde(rename = "ArCl")] - ArCl, - #[serde(rename = "KrFl")] - KrFl, - #[serde(rename = "KrCl")] - KrCl, - #[serde(rename = "XeFl")] - XeFl, - #[serde(rename = "XeCl")] - XeCl, - #[serde(rename = "XeBr")] - XeBr, - #[serde(rename = "N")] - N, - #[serde(rename = "Ar")] - Ar, - #[serde(rename = "Kr")] - Kr, - #[serde(rename = "Xe")] - Xe, - #[serde(rename = "HeNe")] - HeNe, - #[serde(rename = "HeCd")] - HeCd, - #[serde(rename = "CO")] - Co, - #[serde(rename = "CO2")] - Co2, - #[serde(rename = "H2O")] - H2O, - #[serde(rename = "HFl")] - Hfl, - #[serde(rename = "NdGlass")] - NdGlass, - #[serde(rename = "NdYAG")] - NdYag, - #[serde(rename = "ErGlass")] - ErGlass, - #[serde(rename = "ErYAG")] - ErYag, - #[serde(rename = "HoYLF")] - HoYlf, - #[serde(rename = "HoYAG")] - HoYag, - #[serde(rename = "Ruby")] - Ruby, - #[serde(rename = "TiSapphire")] - TiSapphire, - #[serde(rename = "Alexandrite")] - Alexandrite, - #[serde(rename = "Rhodamine6G")] - Rhodamine6G, - #[serde(rename = "CoumarinC30")] - CoumarinC30, - #[serde(rename = "GaAs")] - GaAs, - #[serde(rename = "GaAlAs")] - GaAlAs, - #[serde(rename = "EMinus")] - Eminus, - #[serde(rename = "Other")] - Other, -} -#[derive(Clone, Debug, Serialize, Deserialize)] -pub enum LaserPulseType { - #[serde(rename = "CW")] - Cw, - #[serde(rename = "Single")] - Single, - #[serde(rename = "QSwitched")] - Qswitched, - #[serde(rename = "Repetitive")] - Repetitive, - #[serde(rename = "ModeLocked")] - ModeLocked, - #[serde(rename = "Other")] - Other, -} -#[derive(Clone, Debug, Serialize, Deserialize)] -pub enum LaserType { - #[serde(rename = "Excimer")] - Excimer, - #[serde(rename = "Gas")] - Gas, - #[serde(rename = "MetalVapor")] - MetalVapor, - #[serde(rename = "SolidState")] - SolidState, - #[serde(rename = "Dye")] - Dye, - #[serde(rename = "Semiconductor")] - Semiconductor, - #[serde(rename = "FreeElectron")] - FreeElectron, - #[serde(rename = "Other")] - Other, -} -#[cfg_attr(feature = "python", derive(IntoPyObject))] -#[derive(Clone, Debug, Serialize, Deserialize)] -pub struct LightEmittingDiode { - #[serde(default, rename = "@Manufacturer")] - pub manufacturer: Option, - #[serde(default, rename = "@Model")] - pub model: Option, - #[serde(default, rename = "@SerialNumber")] - pub serial_number: Option, - #[serde(default, rename = "@LotNumber")] - pub lot_number: Option, - #[serde(rename = "@ID")] - pub id: String, - #[serde(default, rename = "@Power")] - pub power: Option, - #[serde( - default = "LightEmittingDiode::default_power_unit", - rename = "@PowerUnit" - )] - pub power_unit: UnitsPower, - #[serde(default, rename = "AnnotationRef")] - pub annotation_ref: Vec, -} -impl LightEmittingDiode { - pub fn default_power_unit() -> UnitsPower { - UnitsPower::mW - } -} -#[cfg_attr(feature = "python", derive(IntoPyObject))] -#[derive(Clone, Debug, Serialize, Deserialize)] -pub struct LightPath { - #[serde(default, rename = "ExcitationFilterRef")] - pub excitation_filter_ref: Vec, - #[serde(default, rename = "DichroicRef")] - pub dichroic_ref: Option, - #[serde(default, rename = "EmissionFilterRef")] - pub emission_filter_ref: Vec, - #[serde(default, rename = "AnnotationRef")] - pub annotation_ref: Vec, -} -#[cfg_attr(feature = "python", derive(IntoPyObject))] -#[derive(Clone, Debug, Serialize, Deserialize)] -pub struct LightSourceType { - #[serde(default, rename = "@Manufacturer")] - pub manufacturer: Option, - #[serde(default, rename = "@Model")] - pub model: Option, - #[serde(default, rename = "@SerialNumber")] - pub serial_number: Option, - #[serde(default, rename = "@LotNumber")] - pub lot_number: Option, - #[serde(rename = "@ID")] - pub id: String, - #[serde(default, rename = "@Power")] - pub power: Option, - #[serde(default = "LightSourceType::default_power_unit", rename = "@PowerUnit")] - pub power_unit: UnitsPower, - #[serde(default, rename = "AnnotationRef")] - pub annotation_ref: Vec, -} -impl LightSourceType { - pub fn default_power_unit() -> UnitsPower { - UnitsPower::mW - } -} -#[cfg_attr(feature = "python", derive(IntoPyObject))] -#[derive(Clone, Debug, Serialize, Deserialize)] -pub enum LightSourceGroup { - #[serde(rename = "Laser")] - Laser(Laser), - #[serde(rename = "Arc")] - Arc(Arc), - #[serde(rename = "Filament")] - Filament(Filament), - #[serde(rename = "LightEmittingDiode")] - LightEmittingDiode(LightEmittingDiode), - #[serde(rename = "GenericExcitationSource")] - GenericExcitationSource(GenericExcitationSource), -} -#[cfg_attr(feature = "python", derive(IntoPyObject))] -#[derive(Clone, Debug, Serialize, Deserialize)] -pub struct LightSourceSettings { - #[serde(rename = "@ID")] - pub id: String, - #[serde(default, rename = "@Attenuation")] - pub attenuation: Option, - #[serde(default, rename = "@Wavelength")] - pub wavelength: Option, - #[serde( - default = "LightSourceSettings::default_wavelength_unit", - rename = "@WavelengthUnit" - )] - pub wavelength_unit: UnitsLength, -} -impl LightSourceSettings { - pub fn default_wavelength_unit() -> UnitsLength { - UnitsLength::nm - } -} -#[cfg_attr(feature = "python", derive(IntoPyObject))] -#[derive(Clone, Debug, Serialize, Deserialize)] -pub struct Line { - #[serde(default, rename = "@FillColor")] - pub fill_color: Option, - #[serde(default, rename = "@FillRule")] - pub fill_rule: Option, - #[serde(default, rename = "@StrokeColor")] - pub stroke_color: Option, - #[serde(default, rename = "@StrokeWidth")] - pub stroke_width: Option, - #[serde( - default = "Line::default_stroke_width_unit", - rename = "@StrokeWidthUnit" - )] - pub stroke_width_unit: UnitsLength, - #[serde(default, rename = "@StrokeDashArray")] - pub stroke_dash_array: Option, - #[serde(default, rename = "@Text")] - pub text: Option, - #[serde(default, rename = "@FontFamily")] - pub font_family: Option, - #[serde(default, rename = "@FontSize")] - pub font_size: Option, - #[serde(default = "Line::default_font_size_unit", rename = "@FontSizeUnit")] - pub font_size_unit: UnitsLength, - #[serde(default, rename = "@FontStyle")] - pub font_style: Option, - #[serde(default, rename = "@Locked")] - pub locked: Option, - #[serde(rename = "@ID")] - pub id: String, - #[serde(default, rename = "@TheZ")] - pub the_z: Option, - #[serde(default, rename = "@TheT")] - pub the_t: Option, - #[serde(default, rename = "@TheC")] - pub the_c: Option, - #[serde(rename = "@X1")] - pub x1: f32, - #[serde(rename = "@Y1")] - pub y1: f32, - #[serde(rename = "@X2")] - pub x2: f32, - #[serde(rename = "@Y2")] - pub y2: f32, - #[serde(default, rename = "@MarkerStart")] - pub marker_start: Option, - #[serde(default, rename = "@MarkerEnd")] - pub marker_end: Option, - #[serde(default, rename = "Transform")] - pub transform: Option, - #[serde(default, rename = "AnnotationRef")] - pub annotation_ref: Vec, -} -impl Line { - pub fn default_stroke_width_unit() -> UnitsLength { - UnitsLength::Pixel - } - pub fn default_font_size_unit() -> UnitsLength { - UnitsLength::Pixel - } -} -#[cfg_attr(feature = "python", derive(IntoPyObject))] -#[derive(Clone, Debug, Serialize, Deserialize)] -pub struct LongAnnotation { - #[serde(rename = "@ID")] - pub id: String, - #[serde(default, rename = "@Namespace")] - pub namespace: Option, - #[serde(default, rename = "@Annotator")] - pub annotator: Option, - #[serde(default, rename = "Description")] - pub description: Option, - #[serde(default, rename = "AnnotationRef")] - pub annotation_ref: Vec, - #[serde(rename = "Value")] - pub value: i64, -} -#[cfg_attr(feature = "python", derive(IntoPyObject))] -#[derive(Clone, Debug, Serialize, Deserialize)] -pub struct MapType { - #[serde(default, rename = "M")] - pub m: Vec, -} -#[cfg_attr(feature = "python", derive(IntoPyObject))] -#[derive(Clone, Debug, Serialize, Deserialize)] -pub struct MapAnnotation { - #[serde(rename = "@ID")] - pub id: String, - #[serde(default, rename = "@Namespace")] - pub namespace: Option, - #[serde(default, rename = "@Annotator")] - pub annotator: Option, - #[serde(default, rename = "Description")] - pub description: Option, - #[serde(default, rename = "AnnotationRef")] - pub annotation_ref: Vec, - #[serde(rename = "Value")] - pub value: MapType, -} -#[cfg_attr(feature = "python", derive(IntoPyObject))] -#[derive(Clone, Debug, Serialize, Deserialize)] -pub struct MapM { - #[serde(default, rename = "@K")] - pub k: Option, - #[serde(rename = "$text")] - pub content: String, -} -#[derive(Clone, Debug, Serialize, Deserialize)] -pub enum MarkerType { - #[serde(rename = "Arrow")] - Arrow, -} -#[cfg_attr(feature = "python", derive(IntoPyObject))] -#[derive(Clone, Debug, Serialize, Deserialize)] -pub struct Mask { - #[serde(default, rename = "@FillColor")] - pub fill_color: Option, - #[serde(default, rename = "@FillRule")] - pub fill_rule: Option, - #[serde(default, rename = "@StrokeColor")] - pub stroke_color: Option, - #[serde(default, rename = "@StrokeWidth")] - pub stroke_width: Option, - #[serde( - default = "Mask::default_stroke_width_unit", - rename = "@StrokeWidthUnit" - )] - pub stroke_width_unit: UnitsLength, - #[serde(default, rename = "@StrokeDashArray")] - pub stroke_dash_array: Option, - #[serde(default, rename = "@Text")] - pub text: Option, - #[serde(default, rename = "@FontFamily")] - pub font_family: Option, - #[serde(default, rename = "@FontSize")] - pub font_size: Option, - #[serde(default = "Mask::default_font_size_unit", rename = "@FontSizeUnit")] - pub font_size_unit: UnitsLength, - #[serde(default, rename = "@FontStyle")] - pub font_style: Option, - #[serde(default, rename = "@Locked")] - pub locked: Option, - #[serde(rename = "@ID")] - pub id: String, - #[serde(default, rename = "@TheZ")] - pub the_z: Option, - #[serde(default, rename = "@TheT")] - pub the_t: Option, - #[serde(default, rename = "@TheC")] - pub the_c: Option, - #[serde(rename = "@X")] - pub x: f32, - #[serde(rename = "@Y")] - pub y: f32, - #[serde(rename = "@Width")] - pub width: f32, - #[serde(rename = "@Height")] - pub height: f32, - #[serde(default, rename = "Transform")] - pub transform: Option, - #[serde(default, rename = "AnnotationRef")] - pub annotation_ref: Vec, - #[serde(rename = "BinData")] - pub bin_data: BinData, -} -impl Mask { - pub fn default_stroke_width_unit() -> UnitsLength { - UnitsLength::Pixel - } - pub fn default_font_size_unit() -> UnitsLength { - UnitsLength::Pixel - } -} -#[derive(Clone, Debug, Serialize, Deserialize)] -pub struct MetadataOnly; -#[cfg_attr(feature = "python", derive(IntoPyObject))] -#[derive(Clone, Debug, Serialize, Deserialize)] -pub struct MicrobeamManipulation { - #[serde(rename = "@ID")] - pub id: String, - #[serde(default, rename = "@Type")] - pub r#type: Option, - #[serde(default, rename = "Description")] - pub description: Option, - #[serde(default, rename = "ROIRef")] - pub roi_ref: Vec, - #[serde(rename = "ExperimenterRef")] - pub experimenter_ref: AnnotationRef, - #[serde(default, rename = "LightSourceSettings")] - pub light_source_settings: Vec, -} -#[derive(Clone, Debug, Serialize, Deserialize)] -pub enum MicrobeamManipulationItemType { - #[serde(rename = "FRAP")] - Frap, - #[serde(rename = "FLIP")] - Flip, - #[serde(rename = "InverseFRAP")] - InverseFrap, - #[serde(rename = "Photoablation")] - Photoablation, - #[serde(rename = "Photoactivation")] - Photoactivation, - #[serde(rename = "Uncaging")] - Uncaging, - #[serde(rename = "OpticalTrapping")] - OpticalTrapping, - #[serde(rename = "Other")] - Other, -} -#[cfg_attr(feature = "python", derive(IntoPyObject))] -#[derive(Clone, Debug, Serialize, Deserialize, Default)] -pub struct MicrobeamManipulationType(pub Vec); -#[cfg_attr(feature = "python", derive(IntoPyObject))] -#[derive(Clone, Debug, Serialize, Deserialize)] -pub struct Microscope { - #[serde(default, rename = "@Manufacturer")] - pub manufacturer: Option, - #[serde(default, rename = "@Model")] - pub model: Option, - #[serde(default, rename = "@SerialNumber")] - pub serial_number: Option, - #[serde(default, rename = "@LotNumber")] - pub lot_number: Option, - #[serde(default, rename = "@Type")] - pub r#type: Option, -} -#[derive(Clone, Debug, Serialize, Deserialize)] -pub enum MicroscopeType { - #[serde(rename = "Upright")] - Upright, - #[serde(rename = "Inverted")] - Inverted, - #[serde(rename = "Dissection")] - Dissection, - #[serde(rename = "Electrophysiology")] - Electrophysiology, - #[serde(rename = "Other")] - Other, -} -#[derive(Clone, Debug, Serialize, Deserialize)] -pub enum NamingConventionType { - #[serde(rename = "letter")] - Letter, - #[serde(rename = "number")] - Number, -} - -/// The root of the metadata, create this by parsing an XML string. -/// ``` -/// use ome_metadata::Ome; -/// -/// let xml = r#" -/// -/// 2025-01-29T14:42:42 -/// -/// -/// -/// -/// -/// -/// -/// -/// "#; -/// -/// let ome: Ome = xml.parse().unwrap(); -/// let image = &ome.image.unwrap()[0]; -/// println!("acquisition date: {:#?}", image.acquisition_date); -/// ``` -#[cfg_attr(feature = "python", derive(IntoPyObject))] -#[derive(Clone, Debug, Serialize, Deserialize)] -pub struct Ome { - #[serde(default, rename = "@UUID")] - pub uuid: Option, - #[serde(default, rename = "@Creator")] - pub creator: Option, - #[serde(rename = "Rights")] - pub rights: Option, - #[serde(default, rename = "Project")] - pub project: Vec, - #[serde(default, rename = "Dataset")] - pub dataset: Vec, - #[serde(default, rename = "Folder")] - pub folder: Vec, - #[serde(default, rename = "Experiment")] - pub experiment: Vec, - #[serde(default, rename = "Plate")] - pub plate: Vec, - #[serde(default, rename = "Screen")] - pub screen: Vec, - #[serde(default, rename = "Experimenter")] - pub experimenter: Vec, - #[serde(default, rename = "ExperimenterGroup")] - pub experimenter_group: Vec, - #[serde(default, rename = "Instrument")] - pub instrument: Vec, - #[serde(default, rename = "Image")] - pub image: Vec, - #[serde(rename = "StructuredAnnotations")] - pub structured_annotations: Option, - #[serde(default, rename = "ROI")] - pub roi: Vec, - #[serde(rename = "BinaryOnly")] - pub binary_only: Option, -} -#[cfg_attr(feature = "python", derive(IntoPyObject))] -#[derive(Clone, Debug, Serialize, Deserialize)] -pub struct Objective { - #[serde(default, rename = "@Manufacturer")] - pub manufacturer: Option, - #[serde(default, rename = "@Model")] - pub model: Option, - #[serde(default, rename = "@SerialNumber")] - pub serial_number: Option, - #[serde(default, rename = "@LotNumber")] - pub lot_number: Option, - #[serde(rename = "@ID")] - pub id: String, - #[serde(default, rename = "@Correction")] - pub correction: Option, - #[serde(default, rename = "@Immersion")] - pub immersion: Option, - #[serde(default, rename = "@LensNA")] - pub lens_na: Option, - #[serde(default, rename = "@NominalMagnification")] - pub nominal_magnification: Option, - #[serde(default, rename = "@CalibratedMagnification")] - pub calibrated_magnification: Option, - #[serde(default, rename = "@WorkingDistance")] - pub working_distance: Option, - #[serde( - default = "Objective::default_working_distance_unit", - rename = "@WorkingDistanceUnit" - )] - pub working_distance_unit: UnitsLength, - #[serde(default, rename = "@Iris")] - pub iris: Option, - #[serde(default, rename = "AnnotationRef")] - pub annotation_ref: Vec, -} -impl Objective { - pub fn default_working_distance_unit() -> UnitsLength { - UnitsLength::um - } -} -#[derive(Clone, Debug, Serialize, Deserialize)] -pub enum ObjectiveCorrectionType { - #[serde(rename = "UV")] - Uv, - #[serde(rename = "PlanApo")] - PlanApo, - #[serde(rename = "PlanFluor")] - PlanFluor, - #[serde(rename = "SuperFluor")] - SuperFluor, - #[serde(rename = "VioletCorrected")] - VioletCorrected, - #[serde(rename = "Achro")] - Achro, - #[serde(rename = "Achromat")] - Achromat, - #[serde(rename = "Fluor")] - Fluor, - #[serde(rename = "Fl")] - Fl, - #[serde(rename = "Fluar")] - Fluar, - #[serde(rename = "Neofluar")] - Neofluar, - #[serde(rename = "Fluotar")] - Fluotar, - #[serde(rename = "Apo")] - Apo, - #[serde(rename = "PlanNeofluar")] - PlanNeofluar, - #[serde(rename = "Other")] - Other, -} -#[derive(Clone, Debug, Serialize, Deserialize)] -pub enum ObjectiveImmersionType { - #[serde(rename = "Oil")] - Oil, - #[serde(rename = "Water")] - Water, - #[serde(rename = "WaterDipping")] - WaterDipping, - #[serde(rename = "Air")] - Air, - #[serde(rename = "Multi")] - Multi, - #[serde(rename = "Glycerol")] - Glycerol, - #[serde(rename = "Other")] - Other, -} -#[cfg_attr(feature = "python", derive(IntoPyObject))] -#[derive(Clone, Debug, Serialize, Deserialize)] -pub struct ObjectiveSettings { - #[serde(rename = "@ID")] - pub id: String, - #[serde(default, rename = "@CorrectionCollar")] - pub correction_collar: Option, - #[serde(default, rename = "@Medium")] - pub medium: Option, - #[serde(default, rename = "@RefractiveIndex")] - pub refractive_index: Option, -} -#[derive(Clone, Debug, Serialize, Deserialize)] -pub enum ObjectiveSettingsMediumType { - #[serde(rename = "Air")] - Air, - #[serde(rename = "Oil")] - Oil, - #[serde(rename = "Water")] - Water, - #[serde(rename = "Glycerol")] - Glycerol, - #[serde(rename = "Other")] - Other, -} -#[cfg_attr(feature = "python", derive(IntoPyObject))] -#[derive(Clone, Debug, Serialize, Deserialize)] -pub struct OmeBinaryOnly { - #[serde(rename = "@MetadataFile")] - pub metadata_file: String, - #[serde(rename = "@UUID")] - pub uuid: String, -} -#[derive(Clone, Debug, Serialize, Deserialize)] -pub enum PixelType { - #[serde(rename = "int8")] - Int8, - #[serde(rename = "int16")] - Int16, - #[serde(rename = "int32")] - Int32, - #[serde(rename = "uint8")] - Uint8, - #[serde(rename = "uint16")] - Uint16, - #[serde(rename = "uint32")] - Uint32, - #[serde(rename = "float")] - Float, - #[serde(rename = "double")] - Double, - #[serde(rename = "complex")] - Complex, - #[serde(rename = "double-complex")] - DoubleComplex, - #[serde(rename = "bit")] - Bit, -} -#[cfg_attr(feature = "python", derive(IntoPyObject))] -#[derive(Clone, Debug, Serialize, Deserialize)] -pub struct Pixels { - #[serde(rename = "@ID")] - pub id: String, - #[serde(rename = "@DimensionOrder")] - pub dimension_order: PixelsDimensionOrderType, - #[serde(rename = "@Type")] - pub r#type: PixelType, - #[serde(default, rename = "@SignificantBits")] - pub significant_bits: Option, - #[serde(default, rename = "@Interleaved")] - pub interleaved: Option, - #[serde(default, rename = "@BigEndian")] - pub big_endian: Option, - #[serde(rename = "@SizeX")] - pub size_x: i32, - #[serde(rename = "@SizeY")] - pub size_y: i32, - #[serde(rename = "@SizeZ")] - pub size_z: i32, - #[serde(rename = "@SizeC")] - pub size_c: i32, - #[serde(rename = "@SizeT")] - pub size_t: i32, - #[serde(default, rename = "@PhysicalSizeX")] - pub physical_size_x: Option, - #[serde( - default = "Pixels::default_physical_size_x_unit", - rename = "@PhysicalSizeXUnit" - )] - pub physical_size_x_unit: UnitsLength, - #[serde(default, rename = "@PhysicalSizeY")] - pub physical_size_y: Option, - #[serde( - default = "Pixels::default_physical_size_y_unit", - rename = "@PhysicalSizeYUnit" - )] - pub physical_size_y_unit: UnitsLength, - #[serde(default, rename = "@PhysicalSizeZ")] - pub physical_size_z: Option, - #[serde( - default = "Pixels::default_physical_size_z_unit", - rename = "@PhysicalSizeZUnit" - )] - pub physical_size_z_unit: UnitsLength, - #[serde(default, rename = "@TimeIncrement")] - pub time_increment: Option, - #[serde( - default = "Pixels::default_time_increment_unit", - rename = "@TimeIncrementUnit" - )] - pub time_increment_unit: UnitsTime, - #[serde(default, rename = "Channel")] - pub channel: Vec, - #[serde(default, rename = "BinData")] - pub bin_data: Vec, - #[serde(default, rename = "TiffData")] - pub tiff_data: Vec, - #[serde(rename = "MetadataOnly")] - pub metadata_only: Option, - #[serde(default, rename = "Plane")] - pub plane: Vec, -} -impl Pixels { - pub fn default_physical_size_x_unit() -> UnitsLength { - UnitsLength::um - } - pub fn default_physical_size_y_unit() -> UnitsLength { - UnitsLength::um - } - pub fn default_physical_size_z_unit() -> UnitsLength { - UnitsLength::um - } - pub fn default_time_increment_unit() -> UnitsTime { - UnitsTime::s - } -} -#[derive(Clone, Debug, Serialize, Deserialize)] -pub enum PixelsDimensionOrderType { - #[serde(rename = "XYZCT")] - Xyzct, - #[serde(rename = "XYZTC")] - Xyztc, - #[serde(rename = "XYCTZ")] - Xyctz, - #[serde(rename = "XYCZT")] - Xyczt, - #[serde(rename = "XYTCZ")] - Xytcz, - #[serde(rename = "XYTZC")] - Xytzc, -} -#[cfg_attr(feature = "python", derive(IntoPyObject))] -#[derive(Clone, Debug, Serialize, Deserialize)] -pub struct Plane { - #[serde(rename = "@TheZ")] - pub the_z: i32, - #[serde(rename = "@TheT")] - pub the_t: i32, - #[serde(rename = "@TheC")] - pub the_c: i32, - #[serde(default, rename = "@DeltaT")] - pub delta_t: Option, - #[serde(default = "Plane::default_delta_t_unit", rename = "@DeltaTUnit")] - pub delta_t_unit: UnitsTime, - #[serde(default, rename = "@ExposureTime")] - pub exposure_time: Option, - #[serde( - default = "Plane::default_exposure_time_unit", - rename = "@ExposureTimeUnit" - )] - pub exposure_time_unit: UnitsTime, - #[serde(default, rename = "@PositionX")] - pub position_x: Option, - #[serde(default = "Plane::default_position_x_unit", rename = "@PositionXUnit")] - pub position_x_unit: UnitsLength, - #[serde(default, rename = "@PositionY")] - pub position_y: Option, - #[serde(default = "Plane::default_position_y_unit", rename = "@PositionYUnit")] - pub position_y_unit: UnitsLength, - #[serde(default, rename = "@PositionZ")] - pub position_z: Option, - #[serde(default = "Plane::default_position_z_unit", rename = "@PositionZUnit")] - pub position_z_unit: UnitsLength, - #[serde(rename = "HashSHA1")] - pub hash_sha1: Option, - #[serde(rename = "AnnotationRef")] - pub annotation_ref: Option, -} -impl Plane { - pub fn default_delta_t_unit() -> UnitsTime { - UnitsTime::s - } - pub fn default_exposure_time_unit() -> UnitsTime { - UnitsTime::s - } - pub fn default_position_x_unit() -> UnitsLength { - UnitsLength::um - } - pub fn default_position_y_unit() -> UnitsLength { - UnitsLength::um - } - pub fn default_position_z_unit() -> UnitsLength { - UnitsLength::um - } -} -#[cfg_attr(feature = "python", derive(IntoPyObject))] -#[derive(Clone, Debug, Serialize, Deserialize)] -pub struct Plate { - #[serde(rename = "@ID")] - pub id: String, - #[serde(default, rename = "@Name")] - pub name: Option, - #[serde(default, rename = "@Status")] - pub status: Option, - #[serde(default, rename = "@ExternalIdentifier")] - pub external_identifier: Option, - #[serde(default, rename = "@ColumnNamingConvention")] - pub column_naming_convention: Option, - #[serde(default, rename = "@RowNamingConvention")] - pub row_naming_convention: Option, - #[serde(default, rename = "@WellOriginX")] - pub well_origin_x: Option, - #[serde( - default = "Plate::default_well_origin_x_unit", - rename = "@WellOriginXUnit" - )] - pub well_origin_x_unit: UnitsLength, - #[serde(default, rename = "@WellOriginY")] - pub well_origin_y: Option, - #[serde( - default = "Plate::default_well_origin_y_unit", - rename = "@WellOriginYUnit" - )] - pub well_origin_y_unit: UnitsLength, - #[serde(default, rename = "@Rows")] - pub rows: Option, - #[serde(default, rename = "@Columns")] - pub columns: Option, - #[serde(default, rename = "@FieldIndex")] - pub field_index: Option, - #[serde(default, rename = "Description")] - pub description: Option, - #[serde(default, rename = "Well")] - pub well: Vec, - #[serde(default, rename = "AnnotationRef")] - pub annotation_ref: Vec, - #[serde(default, rename = "PlateAcquisition")] - pub plate_acquisition: Vec, -} -impl Plate { - pub fn default_well_origin_x_unit() -> UnitsLength { - UnitsLength::um - } - pub fn default_well_origin_y_unit() -> UnitsLength { - UnitsLength::um - } -} -#[cfg_attr(feature = "python", derive(IntoPyObject))] -#[derive(Clone, Debug, Serialize, Deserialize)] -pub struct PlateAcquisition { - #[serde(rename = "@ID")] - pub id: String, - #[serde(default, rename = "@Name")] - pub name: Option, - #[serde(default, rename = "@EndTime")] - pub end_time: Option, - #[serde(default, rename = "@StartTime")] - pub start_time: Option, - #[serde(default, rename = "@MaximumFieldCount")] - pub maximum_field_count: Option, - #[serde(default, rename = "Description")] - pub description: Option, - #[serde(default, rename = "WellSampleRef")] - pub well_sample_ref: Vec, - #[serde(default, rename = "AnnotationRef")] - pub annotation_ref: Vec, -} -#[cfg_attr(feature = "python", derive(IntoPyObject))] -#[derive(Clone, Debug, Serialize, Deserialize)] -pub struct Polygon { - #[serde(default, rename = "@FillColor")] - pub fill_color: Option, - #[serde(default, rename = "@FillRule")] - pub fill_rule: Option, - #[serde(default, rename = "@StrokeColor")] - pub stroke_color: Option, - #[serde(default, rename = "@StrokeWidth")] - pub stroke_width: Option, - #[serde( - default = "Polygon::default_stroke_width_unit", - rename = "@StrokeWidthUnit" - )] - pub stroke_width_unit: UnitsLength, - #[serde(default, rename = "@StrokeDashArray")] - pub stroke_dash_array: Option, - #[serde(default, rename = "@Text")] - pub text: Option, - #[serde(default, rename = "@FontFamily")] - pub font_family: Option, - #[serde(default, rename = "@FontSize")] - pub font_size: Option, - #[serde(default = "Polygon::default_font_size_unit", rename = "@FontSizeUnit")] - pub font_size_unit: UnitsLength, - #[serde(default, rename = "@FontStyle")] - pub font_style: Option, - #[serde(default, rename = "@Locked")] - pub locked: Option, - #[serde(rename = "@ID")] - pub id: String, - #[serde(default, rename = "@TheZ")] - pub the_z: Option, - #[serde(default, rename = "@TheT")] - pub the_t: Option, - #[serde(default, rename = "@TheC")] - pub the_c: Option, - #[serde(rename = "@Points")] - pub points: String, - #[serde(default, rename = "Transform")] - pub transform: Option, - #[serde(default, rename = "AnnotationRef")] - pub annotation_ref: Vec, -} -impl Polygon { - pub fn default_stroke_width_unit() -> UnitsLength { - UnitsLength::Pixel - } - pub fn default_font_size_unit() -> UnitsLength { - UnitsLength::Pixel - } -} -#[cfg_attr(feature = "python", derive(IntoPyObject))] -#[derive(Clone, Debug, Serialize, Deserialize)] -pub struct Polyline { - #[serde(default, rename = "@FillColor")] - pub fill_color: Option, - #[serde(default, rename = "@FillRule")] - pub fill_rule: Option, - #[serde(default, rename = "@StrokeColor")] - pub stroke_color: Option, - #[serde(default, rename = "@StrokeWidth")] - pub stroke_width: Option, - #[serde( - default = "Polyline::default_stroke_width_unit", - rename = "@StrokeWidthUnit" - )] - pub stroke_width_unit: UnitsLength, - #[serde(default, rename = "@StrokeDashArray")] - pub stroke_dash_array: Option, - #[serde(default, rename = "@Text")] - pub text: Option, - #[serde(default, rename = "@FontFamily")] - pub font_family: Option, - #[serde(default, rename = "@FontSize")] - pub font_size: Option, - #[serde(default = "Polyline::default_font_size_unit", rename = "@FontSizeUnit")] - pub font_size_unit: UnitsLength, - #[serde(default, rename = "@FontStyle")] - pub font_style: Option, - #[serde(default, rename = "@Locked")] - pub locked: Option, - #[serde(rename = "@ID")] - pub id: String, - #[serde(default, rename = "@TheZ")] - pub the_z: Option, - #[serde(default, rename = "@TheT")] - pub the_t: Option, - #[serde(default, rename = "@TheC")] - pub the_c: Option, - #[serde(rename = "@Points")] - pub points: String, - #[serde(default, rename = "@MarkerStart")] - pub marker_start: Option, - #[serde(default, rename = "@MarkerEnd")] - pub marker_end: Option, - #[serde(default, rename = "Transform")] - pub transform: Option, - #[serde(default, rename = "AnnotationRef")] - pub annotation_ref: Vec, -} -impl Polyline { - pub fn default_stroke_width_unit() -> UnitsLength { - UnitsLength::Pixel - } - pub fn default_font_size_unit() -> UnitsLength { - UnitsLength::Pixel - } -} -#[cfg_attr(feature = "python", derive(IntoPyObject))] -#[derive(Clone, Debug, Serialize, Deserialize)] -pub struct Project { - #[serde(default, rename = "@Name")] - pub name: Option, - #[serde(rename = "@ID")] - pub id: String, - #[serde(default, rename = "Description")] - pub description: Option, - #[serde(default, rename = "ExperimenterRef")] - pub experimenter_ref: Option, - #[serde(default, rename = "ExperimenterGroupRef")] - pub experimenter_group_ref: Option, - #[serde(default, rename = "DatasetRef")] - pub dataset_ref: Vec, - #[serde(default, rename = "AnnotationRef")] - pub annotation_ref: Vec, -} -#[cfg_attr(feature = "python", derive(IntoPyObject))] -#[derive(Clone, Debug, Serialize, Deserialize)] -pub struct Roi { - #[serde(rename = "@ID")] - pub id: String, - #[serde(default, rename = "@Name")] - pub name: Option, - #[serde(rename = "Union")] - pub union: Option, - #[serde(rename = "AnnotationRef")] - pub annotation_ref: Option, - #[serde(rename = "Description")] - pub description: Option, -} -#[cfg_attr(feature = "python", derive(IntoPyObject))] -#[derive(Clone, Debug, Serialize, Deserialize)] -pub struct Reagent { - #[serde(rename = "@ID")] - pub id: String, - #[serde(default, rename = "@Name")] - pub name: Option, - #[serde(default, rename = "@ReagentIdentifier")] - pub reagent_identifier: Option, - #[serde(default, rename = "Description")] - pub description: Option, - #[serde(default, rename = "AnnotationRef")] - pub annotation_ref: Vec, -} -#[cfg_attr(feature = "python", derive(IntoPyObject))] -#[derive(Clone, Debug, Serialize, Deserialize)] -pub struct Rectangle { - #[serde(default, rename = "@FillColor")] - pub fill_color: Option, - #[serde(default, rename = "@FillRule")] - pub fill_rule: Option, - #[serde(default, rename = "@StrokeColor")] - pub stroke_color: Option, - #[serde(default, rename = "@StrokeWidth")] - pub stroke_width: Option, - #[serde( - default = "Rectangle::default_stroke_width_unit", - rename = "@StrokeWidthUnit" - )] - pub stroke_width_unit: UnitsLength, - #[serde(default, rename = "@StrokeDashArray")] - pub stroke_dash_array: Option, - #[serde(default, rename = "@Text")] - pub text: Option, - #[serde(default, rename = "@FontFamily")] - pub font_family: Option, - #[serde(default, rename = "@FontSize")] - pub font_size: Option, - #[serde( - default = "Rectangle::default_font_size_unit", - rename = "@FontSizeUnit" - )] - pub font_size_unit: UnitsLength, - #[serde(default, rename = "@FontStyle")] - pub font_style: Option, - #[serde(default, rename = "@Locked")] - pub locked: Option, - #[serde(rename = "@ID")] - pub id: String, - #[serde(default, rename = "@TheZ")] - pub the_z: Option, - #[serde(default, rename = "@TheT")] - pub the_t: Option, - #[serde(default, rename = "@TheC")] - pub the_c: Option, - #[serde(rename = "@X")] - pub x: f32, - #[serde(rename = "@Y")] - pub y: f32, - #[serde(rename = "@Width")] - pub width: f32, - #[serde(rename = "@Height")] - pub height: f32, - #[serde(default, rename = "Transform")] - pub transform: Option, - #[serde(default, rename = "AnnotationRef")] - pub annotation_ref: Vec, -} -impl Rectangle { - pub fn default_stroke_width_unit() -> UnitsLength { - UnitsLength::Pixel - } - pub fn default_font_size_unit() -> UnitsLength { - UnitsLength::Pixel - } -} -#[cfg_attr(feature = "python", derive(IntoPyObject))] -#[derive(Clone, Debug, Serialize, Deserialize)] -pub struct Rights { - #[serde(default, rename = "RightsHolder")] - pub rights_holder: Option, - #[serde(default, rename = "RightsHeld")] - pub rights_held: Option, -} -#[cfg_attr(feature = "python", derive(IntoPyObject))] -#[derive(Clone, Debug, Serialize, Deserialize)] -pub struct RoiUnion { - #[serde(default, rename = "ShapeGroup")] - pub shape_group: Vec, -} -#[cfg_attr(feature = "python", derive(IntoPyObject))] -#[derive(Clone, Debug, Serialize, Deserialize)] -pub struct Screen { - #[serde(rename = "@ID")] - pub id: String, - #[serde(default, rename = "@Name")] - pub name: Option, - #[serde(default, rename = "@ProtocolIdentifier")] - pub protocol_identifier: Option, - #[serde(default, rename = "@ProtocolDescription")] - pub protocol_description: Option, - #[serde(default, rename = "@ReagentSetDescription")] - pub reagent_set_description: Option, - #[serde(default, rename = "@ReagentSetIdentifier")] - pub reagent_set_identifier: Option, - #[serde(default, rename = "@Type")] - pub r#type: Option, - #[serde(default, rename = "Description")] - pub description: Option, - #[serde(default, rename = "Reagent")] - pub reagent: Vec, - #[serde(default, rename = "PlateRef")] - pub plate_ref: Vec, - #[serde(default, rename = "AnnotationRef")] - pub annotation_ref: Vec, -} -#[cfg_attr(feature = "python", derive(IntoPyObject))] -#[derive(Clone, Debug, Serialize, Deserialize)] -pub struct ShapeType { - #[serde(default, rename = "@FillColor")] - pub fill_color: Option, - #[serde(default, rename = "@FillRule")] - pub fill_rule: Option, - #[serde(default, rename = "@StrokeColor")] - pub stroke_color: Option, - #[serde(default, rename = "@StrokeWidth")] - pub stroke_width: Option, - #[serde( - default = "ShapeType::default_stroke_width_unit", - rename = "@StrokeWidthUnit" - )] - pub stroke_width_unit: UnitsLength, - #[serde(default, rename = "@StrokeDashArray")] - pub stroke_dash_array: Option, - #[serde(default, rename = "@Text")] - pub text: Option, - #[serde(default, rename = "@FontFamily")] - pub font_family: Option, - #[serde(default, rename = "@FontSize")] - pub font_size: Option, - #[serde( - default = "ShapeType::default_font_size_unit", - rename = "@FontSizeUnit" - )] - pub font_size_unit: UnitsLength, - #[serde(default, rename = "@FontStyle")] - pub font_style: Option, - #[serde(default, rename = "@Locked")] - pub locked: Option, - #[serde(rename = "@ID")] - pub id: String, - #[serde(default, rename = "@TheZ")] - pub the_z: Option, - #[serde(default, rename = "@TheT")] - pub the_t: Option, - #[serde(default, rename = "@TheC")] - pub the_c: Option, - #[serde(default, rename = "Transform")] - pub transform: Option, - #[serde(default, rename = "AnnotationRef")] - pub annotation_ref: Vec, -} -impl ShapeType { - pub fn default_stroke_width_unit() -> UnitsLength { - UnitsLength::Pixel - } - pub fn default_font_size_unit() -> UnitsLength { - UnitsLength::Pixel - } -} -#[derive(Clone, Debug, Serialize, Deserialize)] -pub enum ShapeFillRuleType { - #[serde(rename = "EvenOdd")] - EvenOdd, - #[serde(rename = "NonZero")] - NonZero, -} -#[derive(Clone, Debug, Serialize, Deserialize)] -pub enum ShapeFontStyleType { - #[serde(rename = "Bold")] - Bold, - #[serde(rename = "BoldItalic")] - BoldItalic, - #[serde(rename = "Italic")] - Italic, - #[serde(rename = "Normal")] - Normal, -} -#[cfg_attr(feature = "python", derive(IntoPyObject))] -#[derive(Clone, Debug, Serialize, Deserialize)] -pub enum ShapeGroup { - #[serde(rename = "Rectangle")] - Rectangle(Rectangle), - #[serde(rename = "Mask")] - Mask(Mask), - #[serde(rename = "Point")] - Point(Label), - #[serde(rename = "Ellipse")] - Ellipse(Ellipse), - #[serde(rename = "Line")] - Line(Line), - #[serde(rename = "Polyline")] - Polyline(Polyline), - #[serde(rename = "Polygon")] - Polygon(Polygon), - #[serde(rename = "Label")] - Label(Label), -} -#[cfg_attr(feature = "python", derive(IntoPyObject))] -#[derive(Clone, Debug, Serialize, Deserialize)] -pub struct StageLabel { - #[serde(rename = "@Name")] - pub name: String, - #[serde(default, rename = "@X")] - pub x: Option, - #[serde(default = "StageLabel::default_x_unit", rename = "@XUnit")] - pub x_unit: UnitsLength, - #[serde(default, rename = "@Y")] - pub y: Option, - #[serde(default = "StageLabel::default_y_unit", rename = "@YUnit")] - pub y_unit: UnitsLength, - #[serde(default, rename = "@Z")] - pub z: Option, - #[serde(default = "StageLabel::default_z_unit", rename = "@ZUnit")] - pub z_unit: UnitsLength, -} -impl StageLabel { - pub fn default_x_unit() -> UnitsLength { - UnitsLength::um - } - pub fn default_y_unit() -> UnitsLength { - UnitsLength::um - } - pub fn default_z_unit() -> UnitsLength { - UnitsLength::um - } -} -#[cfg_attr(feature = "python", derive(IntoPyObject))] -#[derive(Clone, Debug, Serialize, Deserialize)] -pub struct StructuredAnnotations { - #[serde(default, rename = "$value")] - pub content: Option, -} -#[allow(clippy::enum_variant_names)] -#[cfg_attr(feature = "python", derive(IntoPyObject))] -#[derive(Clone, Debug, Serialize, Deserialize)] -pub enum StructuredAnnotationsContent { - #[serde(rename = "XMLAnnotation")] - XmlAnnotation(XmlAnnotation), - #[serde(rename = "FileAnnotation")] - FileAnnotation(FileAnnotation), - #[serde(rename = "ListAnnotation")] - ListAnnotation(Annotation), - #[serde(rename = "LongAnnotation")] - LongAnnotation(LongAnnotation), - #[serde(rename = "DoubleAnnotation")] - DoubleAnnotation(DoubleAnnotation), - #[serde(rename = "CommentAnnotation")] - CommentAnnotation(CommentAnnotation), - #[serde(rename = "BooleanAnnotation")] - BooleanAnnotation(BooleanAnnotation), - #[serde(rename = "TimestampAnnotation")] - TimestampAnnotation(CommentAnnotation), - #[serde(rename = "TagAnnotation")] - TagAnnotation(CommentAnnotation), - #[serde(rename = "TermAnnotation")] - TermAnnotation(CommentAnnotation), - #[serde(rename = "MapAnnotation")] - MapAnnotation(MapAnnotation), -} -#[cfg_attr(feature = "python", derive(IntoPyObject))] -#[derive(Clone, Debug, Serialize, Deserialize)] -pub struct TiffData { - #[serde(default = "TiffData::default_ifd", rename = "@IFD")] - pub ifd: i32, - #[serde(default = "TiffData::default_first_z", rename = "@FirstZ")] - pub first_z: i32, - #[serde(default = "TiffData::default_first_t", rename = "@FirstT")] - pub first_t: i32, - #[serde(default = "TiffData::default_first_c", rename = "@FirstC")] - pub first_c: i32, - #[serde(default, rename = "@PlaneCount")] - pub plane_count: Option, - #[serde(default, rename = "UUID")] - pub uuid: Option, -} -impl TiffData { - pub fn default_ifd() -> i32 { - 0 - } - pub fn default_first_z() -> i32 { - 0 - } - pub fn default_first_t() -> i32 { - 0 - } - pub fn default_first_c() -> i32 { - 0 - } -} -#[cfg_attr(feature = "python", derive(IntoPyObject))] -#[derive(Clone, Debug, Serialize, Deserialize)] -pub struct TiffDataUuid { - #[serde(default, rename = "@FileName")] - pub file_name: Option, - #[serde(rename = "$text")] - pub content: String, -} -#[cfg_attr(feature = "python", derive(IntoPyObject))] -#[derive(Clone, Debug, Serialize, Deserialize)] -pub struct TransmittanceRange { - #[serde(default, rename = "@CutIn")] - pub cut_in: Option, - #[serde( - default = "TransmittanceRange::default_cut_in_unit", - rename = "@CutInUnit" - )] - pub cut_in_unit: UnitsLength, - #[serde(default, rename = "@CutOut")] - pub cut_out: Option, - #[serde( - default = "TransmittanceRange::default_cut_out_unit", - rename = "@CutOutUnit" - )] - pub cut_out_unit: UnitsLength, - #[serde(default, rename = "@CutInTolerance")] - pub cut_in_tolerance: Option, - #[serde( - default = "TransmittanceRange::default_cut_in_tolerance_unit", - rename = "@CutInToleranceUnit" - )] - pub cut_in_tolerance_unit: UnitsLength, - #[serde(default, rename = "@CutOutTolerance")] - pub cut_out_tolerance: Option, - #[serde( - default = "TransmittanceRange::default_cut_out_tolerance_unit", - rename = "@CutOutToleranceUnit" - )] - pub cut_out_tolerance_unit: UnitsLength, - #[serde(default, rename = "@Transmittance")] - pub transmittance: Option, -} -impl TransmittanceRange { - pub fn default_cut_in_unit() -> UnitsLength { - UnitsLength::m - } - pub fn default_cut_out_unit() -> UnitsLength { - UnitsLength::m - } - pub fn default_cut_in_tolerance_unit() -> UnitsLength { - UnitsLength::m - } - pub fn default_cut_out_tolerance_unit() -> UnitsLength { - UnitsLength::m - } -} -#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, FromStr, IterVariants)] -pub enum UnitsElectricPotential { - YV, - ZV, - EV, - PV, - TV, - GV, - MV, - kV, - hV, - daV, - V, - dV, - cV, - mV, - #[serde(rename = "µV")] - uV, - nV, - pV, - fV, - aV, - zV, - yV, -} -#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, FromStr, IterVariants)] -pub enum UnitsFrequency { - YHz, - ZHz, - EHz, - PHz, - THz, - GHz, - MHz, - kHz, - hHz, - daHz, - Hz, - dHz, - cHz, - mHz, - #[serde(rename = "µHz")] - uHz, - nHz, - pHz, - fHz, - aHz, - zHz, - yHz, -} -#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, FromStr, IterVariants)] -pub enum UnitsLength { - Ym, - Zm, - Em, - Pm, - Tm, - Gm, - Mm, - km, - hm, - dam, - m, - dm, - cm, - mm, - #[serde(rename = "µm")] - um, - nm, - pm, - fm, - am, - zm, - ym, - #[serde(rename = "Å")] - A, - #[serde(rename = "thou")] - Thou, - #[serde(rename = "li")] - Li, - #[serde(rename = "in")] - In, - #[serde(rename = "ft")] - Ft, - #[serde(rename = "yd")] - Yd, - #[serde(rename = "mi")] - Mi, - #[serde(rename = "ua")] - Ua, - #[serde(rename = "ly")] - Ly, - #[serde(rename = "pc")] - Pc, - #[serde(rename = "pt")] - Pt, - #[serde(rename = "pixel")] - Pixel, - #[serde(rename = "reference frame")] - ReferenceFrame, -} -#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, FromStr, IterVariants)] -pub enum UnitsPower { - YW, - ZW, - EW, - PW, - TW, - GW, - MW, - kW, - hW, - daW, - W, - dW, - cW, - mW, - #[serde(rename = "µW")] - uW, - nW, - pW, - fW, - aW, - zW, - yW, -} -#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, FromStr, IterVariants)] -pub enum UnitsPressure { - YPa, - ZPa, - EPa, - PPa, - TPa, - GPa, - MPa, - kPa, - hPa, - daPa, - Pa, - dPa, - cPa, - mPa, - #[serde(rename = "µPa")] - uPa, - nPa, - pPa, - fPa, - aPa, - zPa, - yPa, - bar, - Mbar, - kbar, - dbar, - cbar, - mbar, - atm, - psi, - Torr, - mTorr, - #[serde(rename = "mm Hg")] - mmHg, -} -#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, FromStr, IterVariants)] -pub enum UnitsTemperature { - #[serde(rename = "°C")] - C, - #[serde(rename = "°F")] - F, - #[serde(rename = "K")] - K, - #[serde(rename = "°R")] - R, -} -#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, FromStr, IterVariants)] -pub enum UnitsTime { - Ys, - Zs, - Es, - Ps, - Ts, - Gs, - Ms, - ks, - hs, - das, - s, - ds, - cs, - ms, - #[serde(rename = "µs")] - us, - ns, - ps, - fs, - r#as, - zs, - ys, - min, - h, - d, -} -#[cfg_attr(feature = "python", derive(IntoPyObject))] -#[derive(Clone, Debug, Serialize, Deserialize)] -pub struct Well { - #[serde(rename = "@ID")] - pub id: String, - #[serde(rename = "@Column")] - pub column: i32, - #[serde(rename = "@Row")] - pub row: i32, - #[serde(default, rename = "@ExternalDescription")] - pub external_description: Option, - #[serde(default, rename = "@ExternalIdentifier")] - pub external_identifier: Option, - #[serde(default, rename = "@Type")] - pub r#type: Option, - #[serde(default = "Well::default_color", rename = "@Color")] - pub color: i32, - #[serde(default, rename = "WellSample")] - pub well_sample: Vec, - #[serde(default, rename = "ReagentRef")] - pub reagent_ref: Option, - #[serde(default, rename = "AnnotationRef")] - pub annotation_ref: Vec, -} -impl Well { - pub fn default_color() -> i32 { - 0 - } -} -#[cfg_attr(feature = "python", derive(IntoPyObject))] -#[derive(Clone, Debug, Serialize, Deserialize)] -pub struct WellSample { - #[serde(rename = "@ID")] - pub id: String, - #[serde(default, rename = "@PositionX")] - pub position_x: Option, - #[serde( - default = "WellSample::default_position_x_unit", - rename = "@PositionXUnit" - )] - pub position_x_unit: UnitsLength, - #[serde(default, rename = "@PositionY")] - pub position_y: Option, - #[serde( - default = "WellSample::default_position_y_unit", - rename = "@PositionYUnit" - )] - pub position_y_unit: UnitsLength, - #[serde(default, rename = "@Timepoint")] - pub timepoint: Option, - #[serde(rename = "@Index")] - pub index: i32, - #[serde(default, rename = "ImageRef")] - pub image_ref: Option, -} -impl WellSample { - pub fn default_position_x_unit() -> UnitsLength { - UnitsLength::um - } - pub fn default_position_y_unit() -> UnitsLength { - UnitsLength::um - } -} -#[cfg_attr(feature = "python", derive(IntoPyObject))] -#[derive(Clone, Debug, Serialize, Deserialize)] -pub struct XmlAnnotation { - #[serde(rename = "@ID")] - pub id: String, - #[serde(default, rename = "@Namespace")] - pub namespace: Option, - #[serde(default, rename = "@Annotator")] - pub annotator: Option, - #[serde(default, rename = "Description")] - pub description: Option, - #[serde(default, rename = "AnnotationRef")] - pub annotation_ref: Vec, - #[serde(rename = "Value")] - pub value: XmlAnnotationValue, -} -#[derive(Clone, Debug, Serialize, Deserialize)] -pub struct XmlAnnotationValue; - -pub trait Convert: PartialEq { - /// conversion factor between this and SI value - fn as_si(&self) -> Result; - - /// convert a value with this unit into another unit - fn convert(&self, unit: &Self, value: f64) -> Result { - if self == unit { - Ok(value) - } else { - Ok(value * self.as_si()? / unit.as_si()?) - } - } -} - -macro_rules! impl_enum_variants { - ($($t:ty $(,)?)*) => { - $( - impl $t { - /// all possible variants of this enum that can be constructed or converted into - pub fn variants() -> Vec { - Self::iter().collect::>() - } - } - )* - }; -} - -impl_enum_variants!( - UnitsElectricPotential, - UnitsFrequency, - UnitsLength, - UnitsPower, - UnitsPressure, - UnitsTemperature, - UnitsTime, -); - -impl Convert for UnitsElectricPotential { - fn as_si(&self) -> Result { - match self { - UnitsElectricPotential::YV => Ok(1e24), - UnitsElectricPotential::ZV => Ok(1e21), - UnitsElectricPotential::EV => Ok(1e18), - UnitsElectricPotential::PV => Ok(1e15), - UnitsElectricPotential::TV => Ok(1e12), - UnitsElectricPotential::GV => Ok(1e9), - UnitsElectricPotential::MV => Ok(1e6), - UnitsElectricPotential::kV => Ok(1e3), - UnitsElectricPotential::hV => Ok(1e2), - UnitsElectricPotential::daV => Ok(1e1), - UnitsElectricPotential::V => Ok(1e0), - UnitsElectricPotential::dV => Ok(1e-1), - UnitsElectricPotential::cV => Ok(1e-2), - UnitsElectricPotential::mV => Ok(1e-3), - UnitsElectricPotential::uV => Ok(1e-6), - UnitsElectricPotential::nV => Ok(1e-9), - UnitsElectricPotential::pV => Ok(1e-12), - UnitsElectricPotential::fV => Ok(1e-15), - UnitsElectricPotential::aV => Ok(1e-18), - UnitsElectricPotential::zV => Ok(1e-21), - UnitsElectricPotential::yV => Ok(1e-24), - } - } -} - -impl Convert for UnitsFrequency { - fn as_si(&self) -> Result { - match self { - UnitsFrequency::YHz => Ok(1e24), - UnitsFrequency::ZHz => Ok(1e21), - UnitsFrequency::EHz => Ok(1e18), - UnitsFrequency::PHz => Ok(1e15), - UnitsFrequency::THz => Ok(1e12), - UnitsFrequency::GHz => Ok(1e9), - UnitsFrequency::MHz => Ok(1e6), - UnitsFrequency::kHz => Ok(1e3), - UnitsFrequency::hHz => Ok(1e2), - UnitsFrequency::daHz => Ok(1e1), - UnitsFrequency::Hz => Ok(1e0), - UnitsFrequency::dHz => Ok(1e-1), - UnitsFrequency::cHz => Ok(1e-2), - UnitsFrequency::mHz => Ok(1e-3), - UnitsFrequency::uHz => Ok(1e-6), - UnitsFrequency::nHz => Ok(1e-9), - UnitsFrequency::pHz => Ok(1e-12), - UnitsFrequency::fHz => Ok(1e-15), - UnitsFrequency::aHz => Ok(1e-18), - UnitsFrequency::zHz => Ok(1e-21), - UnitsFrequency::yHz => Ok(1e-24), - } - } -} - -impl Convert for UnitsLength { - fn as_si(&self) -> Result { - match self { - UnitsLength::Ym => Ok(1e24), - UnitsLength::Zm => Ok(1e21), - UnitsLength::Em => Ok(1e18), - UnitsLength::Pm => Ok(1e15), - UnitsLength::Tm => Ok(1e12), - UnitsLength::Gm => Ok(1e9), - UnitsLength::Mm => Ok(1e6), - UnitsLength::km => Ok(1e3), - UnitsLength::hm => Ok(1e2), - UnitsLength::dam => Ok(1e1), - UnitsLength::m => Ok(1e0), - UnitsLength::dm => Ok(1e-1), - UnitsLength::cm => Ok(1e-2), - UnitsLength::mm => Ok(1e-3), - UnitsLength::um => Ok(1e-6), - UnitsLength::nm => Ok(1e-9), - UnitsLength::pm => Ok(1e-12), - UnitsLength::fm => Ok(1e-15), - UnitsLength::am => Ok(1e-18), - UnitsLength::zm => Ok(1e-21), - UnitsLength::ym => Ok(1e-24), - UnitsLength::A => Ok(1e-10), - UnitsLength::Thou => Ok(2.54e-5), - UnitsLength::Li => Ok(5e2), - UnitsLength::In => Ok(2.54e-2), - UnitsLength::Ft => Ok(3.05e-1), - UnitsLength::Yd => Ok(9.14e-1), - UnitsLength::Mi => Ok(1.609344e3), - UnitsLength::Ua => Ok(1.496e11), - UnitsLength::Ly => Ok(9.461e15), - UnitsLength::Pc => Ok(3.086e16), - UnitsLength::Pt => Ok(3.52778e-4), - UnitsLength::Pixel => Err(Error::SizeOfUnknown("pixel".to_string())), - UnitsLength::ReferenceFrame => Err(Error::SizeOfUnknown("reference frame".to_string())), - } - } -} - -impl Convert for UnitsPower { - fn as_si(&self) -> Result { - match self { - UnitsPower::YW => Ok(1e24), - UnitsPower::ZW => Ok(1e21), - UnitsPower::EW => Ok(1e18), - UnitsPower::PW => Ok(1e15), - UnitsPower::TW => Ok(1e12), - UnitsPower::GW => Ok(1e9), - UnitsPower::MW => Ok(1e6), - UnitsPower::kW => Ok(1e3), - UnitsPower::hW => Ok(1e2), - UnitsPower::daW => Ok(1e1), - UnitsPower::W => Ok(1e0), - UnitsPower::dW => Ok(1e-1), - UnitsPower::cW => Ok(1e-2), - UnitsPower::mW => Ok(1e-3), - UnitsPower::uW => Ok(1e-6), - UnitsPower::nW => Ok(1e-9), - UnitsPower::pW => Ok(1e-12), - UnitsPower::fW => Ok(1e-15), - UnitsPower::aW => Ok(1e-18), - UnitsPower::zW => Ok(1e-21), - UnitsPower::yW => Ok(1e-24), - } - } -} - -impl Convert for UnitsPressure { - fn as_si(&self) -> Result { - match self { - UnitsPressure::YPa => Ok(1e24), - UnitsPressure::ZPa => Ok(1e21), - UnitsPressure::EPa => Ok(1e18), - UnitsPressure::PPa => Ok(1e15), - UnitsPressure::TPa => Ok(1e12), - UnitsPressure::GPa => Ok(1e9), - UnitsPressure::MPa => Ok(1e6), - UnitsPressure::kPa => Ok(1e3), - UnitsPressure::hPa => Ok(1e2), - UnitsPressure::daPa => Ok(1e1), - UnitsPressure::Pa => Ok(1e0), - UnitsPressure::dPa => Ok(1e-1), - UnitsPressure::cPa => Ok(1e-2), - UnitsPressure::mPa => Ok(1e-3), - UnitsPressure::uPa => Ok(1e-6), - UnitsPressure::nPa => Ok(1e-9), - UnitsPressure::pPa => Ok(1e-12), - UnitsPressure::fPa => Ok(1e-15), - UnitsPressure::aPa => Ok(1e-18), - UnitsPressure::zPa => Ok(1e-21), - UnitsPressure::yPa => Ok(1e-24), - UnitsPressure::bar => Ok(1e5), - UnitsPressure::Mbar => Ok(1e11), - UnitsPressure::kbar => Ok(1e8), - UnitsPressure::dbar => Ok(1e4), - UnitsPressure::cbar => Ok(1e3), - UnitsPressure::mbar => Ok(1e2), - UnitsPressure::atm => Ok(1.01325e5), - UnitsPressure::psi => Ok(6.89476e3), - UnitsPressure::Torr => Ok(1.33322e3), - UnitsPressure::mTorr => Ok(1.33322), - UnitsPressure::mmHg => Ok(1.33322e2), - } - } -} - -impl Convert for UnitsTemperature { - fn as_si(&self) -> Result { - match self { - UnitsTemperature::C => Err(Error::TemparatureConversion), - UnitsTemperature::F => Err(Error::TemparatureConversion), - UnitsTemperature::K => Ok(1e1), - UnitsTemperature::R => Ok(5f64 / 9f64), - } - } - - fn convert(&self, unit: &Self, value: f64) -> Result { - match (self, unit) { - (UnitsTemperature::F, UnitsTemperature::C) => Ok((value - 32.) * 5. / 9.), - (UnitsTemperature::K, UnitsTemperature::C) => Ok(value - 273.15), - (UnitsTemperature::R, UnitsTemperature::C) => Ok((value * 5. / 9.) - 273.15), - (UnitsTemperature::C, UnitsTemperature::F) => Ok((value * 9. / 5.) + 32.), - (UnitsTemperature::K, UnitsTemperature::F) => Ok((value * 9. / 5.) - 459.67), - (UnitsTemperature::R, UnitsTemperature::F) => Ok(value - 459.67), - (UnitsTemperature::C, UnitsTemperature::K) => Ok(value + 273.15), - (UnitsTemperature::F, UnitsTemperature::K) => Ok((value + 459.67) * 5. / 9.), - (UnitsTemperature::R, UnitsTemperature::K) => Ok(value * 5. / 9.), - (UnitsTemperature::C, UnitsTemperature::R) => Ok((value + 273.15) * 9. / 5.), - (UnitsTemperature::F, UnitsTemperature::R) => Ok(value + 459.67), - (UnitsTemperature::K, UnitsTemperature::R) => Ok(value * 9. / 5.), - _ => Ok(value), - } - } -} - -impl Convert for UnitsTime { - fn as_si(&self) -> Result { - match self { - UnitsTime::Ys => Ok(1e24), - UnitsTime::Zs => Ok(1e21), - UnitsTime::Es => Ok(1e18), - UnitsTime::Ps => Ok(1e15), - UnitsTime::Ts => Ok(1e12), - UnitsTime::Gs => Ok(1e9), - UnitsTime::Ms => Ok(1e6), - UnitsTime::ks => Ok(1e3), - UnitsTime::hs => Ok(1e2), - UnitsTime::das => Ok(1e1), - UnitsTime::s => Ok(1e0), - UnitsTime::ds => Ok(1e-1), - UnitsTime::cs => Ok(1e-2), - UnitsTime::ms => Ok(1e-3), - UnitsTime::us => Ok(1e-6), - UnitsTime::ns => Ok(1e-9), - UnitsTime::ps => Ok(1e-12), - UnitsTime::fs => Ok(1e-15), - UnitsTime::r#as => Ok(1e-18), - UnitsTime::zs => Ok(1e-21), - UnitsTime::ys => Ok(1e-24), - UnitsTime::min => Ok(6e1), - UnitsTime::h => Ok(3.6e2), - UnitsTime::d => Ok(8.64e4), - } - } -} diff --git a/src/py.rs b/src/py.rs deleted file mode 100644 index c2036cb..0000000 --- a/src/py.rs +++ /dev/null @@ -1,99 +0,0 @@ -use crate::Ome; -use crate::ome::{ - Convert, UnitsElectricPotential, UnitsFrequency, UnitsLength, UnitsPower, UnitsPressure, - UnitsTemperature, UnitsTime, -}; -use pyo3::exceptions::PyValueError; -use pyo3::prelude::*; - -impl From for PyErr { - fn from(err: crate::error::Error) -> PyErr { - PyErr::new::(err.to_string()) - } -} - -macro_rules! impl_enum_into_py_object { - ($($s:ident: $t:ty $(,)?)*) => { - $( - #[pyclass(module = "ome_metadata.ome_metadata_rs")] - pub struct $s { - inner: $t, - } - - #[pymethods] - impl $s { - #[new] - fn new(unit: &str) -> PyResult { - match unit.parse() { - Ok(unit) => Ok(Self { inner: unit }), - Err(_) => Err(PyErr::new::(format!("Invalid unit: {}", unit))) - } - } - - /// convert a value between units - fn convert(&self, unit: &str, value: f64) -> PyResult { - match unit.parse() { - Ok(unit) => Ok(self.inner.convert(&unit, value)?), - Err(_) => Err(PyErr::new::(format!("Invalid unit: {}", unit))) - } - } - - /// all possible variants of this enum that can be constructed or converted into - #[staticmethod] - fn variants() -> Vec { - <$t>::variants().iter().map(|v| format!("{:?}", v)).collect() - } - - fn __repr__(&self) -> String { - format!("{:?}", self.inner) - } - - fn __str__(&self) -> String { - format!("{:?}", self.inner) - } - - fn __getnewargs__(&self) -> (String,) { - (format!("{:?}", self.inner),) - } - } - - impl<'py> IntoPyObject<'py> for $t { - type Target = $s; - type Output = Bound<'py, Self::Target>; - type Error = PyErr; - fn into_pyobject(self, py: Python<'py>) -> PyResult { - Bound::new(py, $s { inner: self }) - } - } - )* - }; -} - -impl_enum_into_py_object! { - ElectricPotential: UnitsElectricPotential - Frequency: UnitsFrequency - Length: UnitsLength - Power: UnitsPower - Pressure: UnitsPressure - Temperature: UnitsTemperature - Time: UnitsTime -} - -#[pyfunction] -fn ome(text: &str) -> PyResult { - Ok(text.parse()?) -} - -#[pymodule] -#[pyo3(name = "ome_metadata_rs")] -fn ome_metadata_rs(m: &Bound<'_, PyModule>) -> PyResult<()> { - m.add_class::()?; - m.add_class::()?; - m.add_class::()?; - m.add_class::()?; - m.add_class::()?; - m.add_class::()?; - m.add_class::