diff --git a/.github/scripts/message_wheel_smoke.py b/.github/scripts/message_wheel_smoke.py new file mode 100644 index 00000000000..2b8199e3ac7 --- /dev/null +++ b/.github/scripts/message_wheel_smoke.py @@ -0,0 +1,33 @@ +#!/usr/bin/env python3 +# Copyright 2026 Dimensional Inc. +# +# 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. + +"""Verify the standalone built-in wheel without installing the robot runtime.""" + +import json +from pathlib import Path + +import dimos_generated as messages +from dimos_generated_schemas.provider import package_root + +assert messages.__dimos_version__ == "0.1.0" +header = messages.std_msgs.msg.Header() +assert type(header).decode(header.encode()).encode() == header.encode() +root = Path(package_root()) +metadata = json.loads((root / "message-package.json").read_text()) +assert metadata["shared"] +assert "std_msgs/msg/Header" in metadata["owned"] +assert (root / "schemas/std_msgs/msg/Header.msg").is_file() +assert (root / "lib/cmake/dimos_generated/dimos_generatedConfig.cmake").is_file() +assert (root / "rust/Cargo.toml").is_file() diff --git a/dimos/cli/commands/build.py b/dimos/cli/commands/build.py new file mode 100644 index 00000000000..e05e5b9031a --- /dev/null +++ b/dimos/cli/commands/build.py @@ -0,0 +1,47 @@ +# Copyright 2026 Dimensional Inc. +# +# 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. + +"""Build external message packages without rebuilding the DimOS runtime.""" + +from importlib import import_module +from pathlib import Path +from subprocess import CalledProcessError + +import typer + + +def build( + project: Path = typer.Option(Path("."), "--project", help="Message project directory."), + language: list[str] = typer.Option( + [], "--language", help="Build only this language; repeatable." + ), + install: bool = typer.Option( + False, "--install", help="Also install the wheel into the active virtualenv." + ), + offline: bool = typer.Option( + False, "--offline", help="Require cached native/Cargo dependencies; do not download." + ), +) -> None: + """Discover, generate and build this project's custom message packages.""" + try: + core = import_module("dimos_message_project.build") + config = core.Project.load(project) + artifacts = core.build_project( + config, tuple(language) or None, install=install, offline=offline + ) + for kind, path in artifacts.items(): + typer.echo(f"{kind}: {path}") + except (ValueError, RuntimeError, FileNotFoundError, CalledProcessError) as error: + typer.echo(f"build: {error}", err=True) + raise typer.Exit(1) from error diff --git a/dimos/cli/dimos.py b/dimos/cli/dimos.py index e64bf03e11d..9e4b11d4bb5 100644 --- a/dimos/cli/dimos.py +++ b/dimos/cli/dimos.py @@ -51,13 +51,13 @@ from dimos.cli.cloud import login as cloud_login, logout as cloud_logout, whoami as cloud_whoami from dimos.cli.commands.apriltag import apriltag from dimos.cli.commands.bake import bake +from dimos.cli.commands.build import build from dimos.cli.commands.cameracalibrate import cameracalibrate from dimos.cli.commands.data import data_app from dimos.cli.commands.dataprep import dataprep_app from dimos.cli.commands.docs import docs from dimos.cli.commands.global_options import create_dynamic_callback from dimos.cli.commands.graph import graph -from dimos.cli.commands.host import host_app from dimos.cli.commands.info import list_blueprints, show_config from dimos.cli.commands.lifecycle import log_cmd, restart, run, status, stop from dimos.cli.commands.map import map_app @@ -109,6 +109,7 @@ def cli_main() -> None: main.add_typer(hardware_app, name="hardware") main.add_typer(data_app, name="data") main.add_typer(go2tool_app, name="go2tool") +main.command()(build) main.command()(shell) main.add_typer(cache_app, name="cache") main.command("login")(cloud_login) @@ -119,7 +120,6 @@ def cli_main() -> None: main.command()(stop) main.command("log")(log_cmd) main.add_typer(mcp_app, name="mcp") -main.add_typer(host_app, name="host") main.command("agent-send")(agent_send_cmd) main.command()(restart) main.command()(show_config) @@ -141,6 +141,7 @@ def cli_main() -> None: main.command(context_settings={"allow_extra_args": True, "ignore_unknown_options": True})(top) main.add_typer(topic_app, name="topic") main.add_typer(map_app, name="map") + main.add_typer(dataprep_app, name="dataprep") from dimos.memory.cli.app import mem_app diff --git a/dimos/hardware/sensors/lidar/fastlio2/cpp/flake.lock b/dimos/hardware/sensors/lidar/fastlio2/cpp/flake.lock index 11dd4fa4afb..196d160769a 100644 --- a/dimos/hardware/sensors/lidar/fastlio2/cpp/flake.lock +++ b/dimos/hardware/sensors/lidar/fastlio2/cpp/flake.lock @@ -28,11 +28,11 @@ }, "locked": { "dir": "native/cpp", - "lastModified": 1792431336, - "narHash": "sha256-W0biIt+6oH7bBHt44kV4J411Y3AUsuMkQ7OsS45BxDE=", + "lastModified": 1792432073, + "narHash": "sha256-5BgFoVp3/X5bKasI5G+f41sqVGAnZ4VPi1w3eC6+DIM=", "owner": "dimensionalOS", "repo": "dimos", - "rev": "fbccb5c45eb84a7f65413a37cba7afe3fe2d8008", + "rev": "ea1d296b163d325d2dea782c4057dbaa3b697fc4", "type": "github" }, "original": { diff --git a/dimos/message_codegen/test_builtin_artifacts.py b/dimos/message_codegen/test_builtin_artifacts.py new file mode 100644 index 00000000000..78789c06c6b --- /dev/null +++ b/dimos/message_codegen/test_builtin_artifacts.py @@ -0,0 +1,91 @@ +# Copyright 2026 Dimensional Inc. +# +# 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. + +import json +import os +from pathlib import Path +import subprocess +import tarfile + +from dimos_cdrgen.definitions import Definitions +from dimos_cdrgen.native_build import prepare_cpp +from dimos_message_project.project import Project +import pytest + +from dimos.message_codegen.native_build import write_cmake_toolchain + + +def test_builtin_native_artifact_version_and_relocated_consumer(tmp_path): + location = os.environ.get("DIMOS_BUILTIN_PACKAGE") + if not location: + pytest.skip("Set DIMOS_BUILTIN_PACKAGE for native source artifact acceptance") + output = Path(location).resolve() + root = Path(__file__).resolve().parents[2] + version = Project.load(root / "packages/dimos-generated").version + metadata = json.loads((output / "message-package.json").read_text()) + assert metadata["version"] == version + assert metadata["shared"] + assert set(metadata["owned"]) == { + message.name for message in Definitions([], installed=True).resolve() + } + assert (output / "dist" / f"dimos-generated-messages-{version}.crate").is_file() + relocated = tmp_path / "relocated" + relocated.mkdir() + with tarfile.open(output / "dist" / f"dimos-messages-sources-{version}.tar.gz") as archive: + archive.extractall(relocated, filter="data") + assert json.loads((relocated / "message-package.json").read_text()) == metadata + sources = { + name: Path(path) + for name, path in json.loads(os.environ.get("DIMOS_NATIVE_SOURCE_DIRS", "{}")).items() + } + cache = os.environ.get("DIMOS_NATIVE_TEST_CACHE") + prefix = prepare_cpp( + relocated, + cache=Path(cache) if cache else None, + offline=os.environ.get("DIMOS_OFFLINE") == "1", + source_dirs=sources or None, + ) + toolchain = write_cmake_toolchain(prefix, tmp_path / "toolchain.cmake") + source = tmp_path / "app" + source.mkdir() + (source / "CMakeLists.txt").write_text(f"""cmake_minimum_required(VERSION 3.20) +project(external_builtin LANGUAGES CXX) +find_package(dimos_generated {version} EXACT CONFIG REQUIRED) +add_executable(check main.cpp) +target_compile_features(check PRIVATE cxx_std_17) +target_include_directories(check PRIVATE "{root}/native/cpp/include") +target_link_libraries(check PRIVATE dimos_generated::messages) +""") + (source / "main.cpp").write_text("""#include +#include +int main() { + std_msgs::msg::Header h; h.frame_id = "outside-checkout"; h.stamp.sec = 17; + auto result = dimos::native::cdr_decode(dimos::native::cdr_encode(h)); + return result.frame_id == h.frame_id && result.stamp.sec == 17 ? 0 : 1; +} +""") + build = tmp_path / "build" + subprocess.run( + [ + "cmake", + "-S", + str(source), + "-B", + str(build), + f"-DCMAKE_TOOLCHAIN_FILE={toolchain}", + ], + check=True, + ) + subprocess.run(["cmake", "--build", str(build), "--parallel", "2"], check=True) + subprocess.run([str(build / "check")], check=True) diff --git a/dimos/message_codegen/test_builtin_catalog.py b/dimos/message_codegen/test_builtin_catalog.py index 682ec1babfb..23c940c4fd1 100644 --- a/dimos/message_codegen/test_builtin_catalog.py +++ b/dimos/message_codegen/test_builtin_catalog.py @@ -36,7 +36,7 @@ def test_unlisted_sources_do_not_expand_the_public_catalog(tmp_path): manifest = json.loads( (source / "dimos_generated_schemas/package/message-package.json").read_text() ) - assert len(manifest["owned"]) == 73 + assert len(manifest["owned"]) == 78 assert "extra_msgs/msg/NotExported" not in manifest["owned"] assert "builtin_interfaces/msg/Time" in manifest["owned"] diff --git a/dimos/message_codegen/test_builtin_install.py b/dimos/message_codegen/test_builtin_install.py index 20ca8b1adce..0b709e6b0f1 100644 --- a/dimos/message_codegen/test_builtin_install.py +++ b/dimos/message_codegen/test_builtin_install.py @@ -38,7 +38,7 @@ assert type(r.header) is Header and r == m assert type(pickle.loads(pickle.dumps(m)).header) is Header assert 'MSG: std_msgs/Header' in schema(m.__msgtype__) -assert len(message_types()) == 73 +assert len(message_types()) == 78 assert 'visualization_msgs/msg/Marker' not in message_types() root = Path(package_root()) assert (root / 'schema-sources.json').is_file() diff --git a/dimos/message_codegen/test_builtin_preparation.py b/dimos/message_codegen/test_builtin_preparation.py index 3cc53553c76..82d816bc161 100644 --- a/dimos/message_codegen/test_builtin_preparation.py +++ b/dimos/message_codegen/test_builtin_preparation.py @@ -48,12 +48,12 @@ def no_network(*args, **kwargs): monkeypatch.setattr("dimos_cdrgen.source_inputs.requests.get", no_network) inputs = prepare(cache, offline=True, project=project) - assert len(list(inputs.rglob("*.msg"))) == 73 + assert len(list(inputs.rglob("*.msg"))) == 78 output = generate(project) resources = output / "dimos_generated_schemas/package" manifest = json.loads((resources / "message-package.json").read_text()) - assert len(manifest["owned"]) == 73 - assert len(list(project.glob("custom/dimos_msgs/msg/*.msg"))) == 14 + assert len(manifest["owned"]) == 78 + assert len(list(project.glob("custom/dimos_msgs/msg/*.msg"))) == 19 lock = json.loads((project / "schema-sources.json").read_text()) assert all(len(item["sha256"]) == 64 for item in lock["sources"]) assert (resources / "dimos_msgs-LICENSE").is_file() diff --git a/dimos/message_codegen/test_documented_project.py b/dimos/message_codegen/test_documented_project.py new file mode 100644 index 00000000000..26f62720557 --- /dev/null +++ b/dimos/message_codegen/test_documented_project.py @@ -0,0 +1,36 @@ +# Copyright 2026 Dimensional Inc. +# +# 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. + +from pathlib import Path +import re + + +def test_documented_sources_match_compiled_example(): + root = Path(__file__).resolve().parents[2] + document = (root / "docs/development/messages-external-project.md").read_text() + blocks = re.findall(r"\n```[^\n]*\n(.*?)```", document, re.S) + assert len(blocks) >= 8 + for name, snippet in blocks: + source = (root / name).read_text() + if name.endswith((".py", ".cpp", ".rs")): + lines = source.splitlines() + comment = "#" if name.endswith(".py") else "//" + while lines and (lines[0].startswith(comment) or not lines[0].strip()): + lines.pop(0) + if lines and lines[0].startswith(chr(34) * 3): + lines.pop(0) + while lines and not lines[0].strip(): + lines.pop(0) + source = "\n".join(lines) + "\n" + assert snippet == source, name diff --git a/dimos/message_codegen/test_ownership_native.py b/dimos/message_codegen/test_ownership_native.py new file mode 100644 index 00000000000..74d1f98dfc7 --- /dev/null +++ b/dimos/message_codegen/test_ownership_native.py @@ -0,0 +1,265 @@ +# Copyright 2026 Dimensional Inc. +# +# 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. + +import json +import os +from pathlib import Path +import shutil +import subprocess +import sys + +from dimos_cdrgen.generate import generate +from dimos_cdrgen.native_build import prepare_cpp +from dimos_cdrgen.ownership import Dependency +from dimos_cdrgen.registry import schema_roots +from dimos_message_project.build import local_cargo_dependency +from mcap.reader import make_reader +import pytest +from rosbags.typesys import Stores, get_types_from_msg, get_typestore + +from dimos.message_codegen.native_build import write_cmake_toolchain +from dimos.protocol.cdr_mcap import CdrMcapWriter + + +@pytest.fixture(autouse=True) +def restore_reference_types_module(): + # Independent oracle stores own a process-global module. Restore it so they + # do not invalidate the canonical registry's native class pickle identities. + previous = sys.modules.get("rosbags.usertypes") + try: + yield + finally: + if previous is None: + sys.modules.pop("rosbags.usertypes", None) + else: + sys.modules["rosbags.usertypes"] = previous + + +def test_separate_packages_share_types_and_exchange_cdr(tmp_path, monkeypatch): + if os.environ.get("DIMOS_NATIVE_ACCEPTANCE") != "1": + pytest.skip("Set DIMOS_NATIVE_ACCEPTANCE=1 to run the compiled ownership contract") + root = Path(__file__).resolve().parents[2] + source = tmp_path / "interfaces/custom_msgs/msg/Reading.msg" + source.parent.mkdir(parents=True) + source.write_text("std_msgs/Header header\nfloat64 value\n") + base, custom = tmp_path / "base", tmp_path / "custom" + generate(list(schema_roots()), base, ["std_msgs/msg/Header"], "ownership_base", shared=True) + generate( + [source.parents[2]], + custom, + ["custom_msgs/msg/Reading"], + "ownership_custom", + dependencies=(Dependency.load(base),), + shared=True, + ) + monkeypatch.syspath_prepend(str(base / "python")) + sources = { + name: Path(path) + for name, path in json.loads(os.environ.get("DIMOS_NATIVE_SOURCE_DIRS", "{}")).items() + } + cache = os.environ.get("DIMOS_NATIVE_TEST_CACHE") + prefix = prepare_cpp( + custom, + cache=Path(cache) if cache else None, + offline=os.environ.get("DIMOS_OFFLINE") == "1", + source_dirs=sources or None, + ) + toolchain = write_cmake_toolchain(prefix, tmp_path / "toolchain.cmake") + (tmp_path / "dimos_message_project").symlink_to(Path(__file__).parent, target_is_directory=True) + env = { + **os.environ, + "PYTHONPATH": os.pathsep.join( + [str(tmp_path), str(base / "python"), str(custom / "python")] + ), + } + bootstrap = """ +from pathlib import Path +from dimos_cdrgen import registry +registry.providers = lambda: () +registry.initialize((Path("base"), Path("custom")), discover=False) +""" + python = """ +from ownership_base.std_msgs.msg import Header +from ownership_base.builtin_interfaces.msg import Time +from ownership_custom.custom_msgs.msg import Reading +from pathlib import Path +h = Header(stamp=Time(sec=0, nanosec=0), frame_id='map') +h.stamp.sec = 17 +h.stamp.nanosec = 123456789 +msg = Reading(header=h, value=20.5) +assert type(msg.header) is Header +msg.header = h +assert type(registry.decode(registry.encode(msg), Reading).header) is Header +Path('input.cdr').write_bytes(registry.encode(msg)) +""" + subprocess.run([sys.executable, "-c", bootstrap + python], env=env, cwd=tmp_path, check=True) + consumer = tmp_path / "consumer" + consumer.mkdir() + (consumer / "CMakeLists.txt").write_text(f"""cmake_minimum_required(VERSION 3.20) +project(ownership_consumer LANGUAGES CXX) +find_package(ownership_custom CONFIG REQUIRED) +add_executable(consumer main.cpp) +target_compile_features(consumer PRIVATE cxx_std_17) +target_include_directories(consumer PRIVATE "{root}/native/cpp/include") +target_link_libraries(consumer PRIVATE ownership_custom::messages) +""") + (consumer / "main.cpp").write_text("""#include +#include +#include +#include +#include +#include +static_assert(std::is_same_v); +int main() { + std::ifstream in("input.cdr", std::ios::binary); + std::vector bytes((std::istreambuf_iterator(in)), {}); + auto msg = dimos::native::cdr_decode(bytes); + std_msgs::msg::Header header = msg.header; msg.header = header; + msg.value += 1; + auto out = dimos::native::cdr_encode(msg); + std::ofstream file("cpp.cdr", std::ios::binary); + file.write(reinterpret_cast(out.data()), out.size()); + return file ? 0 : 1; +} +""") + subprocess.run( + [ + "cmake", + "-S", + str(consumer), + "-B", + str(consumer / "build"), + f"-DCMAKE_TOOLCHAIN_FILE={toolchain}", + ], + check=True, + ) + subprocess.run(["cmake", "--build", str(consumer / "build"), "-j", "2"], check=True) + subprocess.run([str(consumer / "build/consumer")], cwd=tmp_path, check=True) + manifest = custom / "rust/Cargo.toml" + manifest.write_text( + local_cargo_dependency(manifest.read_text(), "ownership_base").replace( + "../ownership_base", str(base / "rust") + ) + ) + (custom / "rust/src/bin").mkdir() + ( + custom / "rust/src/bin/check.rs" + ).write_text("""use ownership_custom_messages::custom_msgs::msg::reading::Reading; +use ownership_base_messages::std_msgs::msg::header::Header; +fn main() { + let wire = std::fs::read("cpp.cdr").unwrap(); + assert_eq!(&wire[..4], &[0, 1, 0, 0]); + let (mut msg, consumed) = re_cdr::from_bytes::(&wire[4..]).unwrap(); + assert_eq!(consumed, wire.len() - 4); + let header: Header = msg.header; msg.header = header; + msg.value += 1.0; + let mut wire = vec![0, 1, 0, 0]; + wire.extend(re_cdr::to_vec::<_, re_cdr::LittleEndian>(&msg).unwrap()); + std::fs::write("rust.cdr", wire).unwrap(); +} +""") + subprocess.run( + [ + "cargo", + "run", + "--offline", + "--manifest-path", + str(custom / "rust/Cargo.toml"), + "--bin", + "check", + ], + cwd=tmp_path, + check=True, + ) + subprocess.run( + [ + sys.executable, + "-c", + bootstrap + + """ +from ownership_base.std_msgs.msg import Header +from ownership_base.builtin_interfaces.msg import Time +from ownership_custom.custom_msgs.msg import Reading +from pathlib import Path +from rosbags.typesys import Stores, get_typestore, get_types_from_msg +msg = registry.decode(Path('rust.cdr').read_bytes(), Reading) +assert type(msg.header) is Header +assert (msg.value, msg.header.frame_id, msg.header.stamp.nanosec) == (22.5, 'map', 123456789) +reference = get_typestore(Stores.ROS2_JAZZY) +reference.register(get_types_from_msg(registry.schema(Reading.__msgtype__), Reading.__msgtype__)) +assert reference.deserialize_cdr(registry.encode(msg), Reading.__msgtype__).value == 22.5 +""", + ], + cwd=tmp_path, + env=env, + check=True, + ) + # Public source manifests are validated before classes are exposed. + manifest_path = base / "message-package.json" + installed_manifest = base / "python/ownership_base_schemas/package/message-package.json" + original = manifest_path.read_text() + for key, value, error in ( + ("version", "99.0.0", "Dependency version mismatch"), + ("schemas", {}, "Message schema digest mismatch"), + ): + changed = json.loads(original) + changed[key] = value + manifest_path.write_text(json.dumps(changed)) + installed_manifest.write_text(json.dumps(changed)) + try: + result = subprocess.run( + [sys.executable, "-c", bootstrap], + env=env, + cwd=tmp_path, + capture_output=True, + text=True, + ) + assert result.returncode != 0 + assert error in result.stderr + finally: + manifest_path.write_text(original) + installed_manifest.write_text(original) + + # Playback has only the recording: imported dependency schemas must be embedded. + name = "custom_msgs/msg/Reading" + schema = json.loads((custom / "schemas.json").read_text())[name] + recording = tmp_path / "custom.mcap" + with CdrMcapWriter(recording) as writer: + writer.write( + "/reading", + (tmp_path / "rust.cdr").read_bytes(), + schema_name=name, + schema=schema, + log_time_ns=1, + ) + with recording.open("rb") as stream: + [(stored, channel, message)] = list(make_reader(stream).iter_messages()) + assert channel.message_encoding == "cdr" + assert stored.encoding == "ros2msg" + reference = get_typestore(Stores.EMPTY) + reference.register(get_types_from_msg(stored.data.decode(), stored.name)) + decoded = reference.deserialize_cdr(message.data, stored.name) + assert (decoded.value, decoded.header.frame_id, decoded.header.stamp.nanosec) == ( + 22.5, + "map", + 123456789, + ) + + destination = os.environ.get("DIMOS_OWNERSHIP_EVIDENCE") + if destination: + evidence = Path(destination) + evidence.mkdir(parents=True, exist_ok=True) + for name in ("input.cdr", "cpp.cdr", "rust.cdr", "custom.mcap"): + shutil.copy2(tmp_path / name, evidence / name) + shutil.copytree(custom / "cpp/custom_msgs", evidence / "custom_msgs", dirs_exist_ok=True) diff --git a/dimos/message_codegen/test_project.py b/dimos/message_codegen/test_project.py new file mode 100644 index 00000000000..4f6b093d11e --- /dev/null +++ b/dimos/message_codegen/test_project.py @@ -0,0 +1,265 @@ +# Copyright 2026 Dimensional Inc. +# +# 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. + +import json +from pathlib import Path +import subprocess +import tarfile +from types import SimpleNamespace + +from dimos_cdrgen.generate import generate +from dimos_cdrgen.registry import schema_roots +from dimos_message_project.backend import build_sdist, get_requires_for_build_wheel +from dimos_message_project.build import build_project +import dimos_message_project.project as project_module +from dimos_message_project.project import Project, prepare +import pytest + + +def project(tmp_path, definition="float64 value\n"): + (tmp_path / "pyproject.toml").write_text("""[project] +name = "example-messages" +version = "1.2.3" +[tool.dimos.messages] +dependencies = {} +""") + source = tmp_path / "interfaces/example_msgs/msg/Reading.msg" + source.parent.mkdir(parents=True) + source.write_text(definition) + return Project.load(tmp_path), source + + +def test_defaults_and_cache_reuse_without_touching_generated_files(tmp_path): + config, _ = project(tmp_path) + output = prepare(config) + header = output / "python/example_messages/_types.pyi" + stamp = header.stat().st_mtime_ns + assert config.module == "example_messages" + assert config.languages == ("python",) + assert prepare(config) == output + assert header.stat().st_mtime_ns == stamp + + +def test_schema_edits_deletion_and_rename_remove_stale_outputs(tmp_path): + config, source = project(tmp_path) + old = source.with_name("Old.msg") + old.write_text("uint32 number\n") + output = prepare(config) + assert (output / "schemas/example_msgs/msg/Old.msg").is_file() + old.unlink() + source.rename(source.with_name("Renamed.msg")) + prepare(config) + assert not (output / "schemas/example_msgs/msg/Old.msg").exists() + assert not (output / "schemas/example_msgs/msg/Reading.msg").exists() + assert (output / "schemas/example_msgs/msg/Renamed.msg").is_file() + source.with_name("Renamed.msg").write_text("int32 replacement\n") + prepare(config) + assert "replacement" in (output / "python/example_messages/_types.pyi").read_text() + + +def test_missing_or_modified_generated_file_is_repaired(tmp_path): + config, _ = project(tmp_path) + output = prepare(config) + header = output / "python/example_messages/_types.pyi" + original = header.read_bytes() + header.write_text("corrupt") + prepare(config) + assert header.read_bytes() == original + header.unlink() + prepare(config) + assert header.read_bytes() == original + + +def test_missing_standard_type_owner_is_not_silently_regenerated(tmp_path): + config, _ = project(tmp_path, "std_msgs/Header header\n") + with pytest.raises(ValueError, match="unresolved message dependency"): + prepare(config) + assert not config.output.exists() + + +def test_invalid_input_keeps_last_successful_generation(tmp_path): + config, source = project(tmp_path) + output = prepare(config) + state = (output / "generation.json").read_bytes() + source.write_text("unknown_msgs/Absent value\n") + with pytest.raises(ValueError, match="unresolved"): + prepare(config) + assert (output / "generation.json").read_bytes() == state + + +def test_config_rejects_typo_instead_of_ignoring_it(tmp_path): + config, _ = project(tmp_path) + with (tmp_path / "pyproject.toml").open("a") as stream: + stream.write('langauges = ["rust"]\n') + with pytest.raises(ValueError, match="Unknown message configuration"): + Project.load(tmp_path) + + +def test_python_backend_never_requests_native_sdk_or_rust(tmp_path, monkeypatch): + project(tmp_path) + monkeypatch.chdir(tmp_path) + assert get_requires_for_build_wheel() == [ + "setuptools>=70", + "wheel", + ] + name = build_sdist(str(tmp_path / "dist")) + with tarfile.open(tmp_path / "dist" / name) as archive: + assert sorted(archive.getnames()) == [ + "example_messages-1.2.3/interfaces/example_msgs/msg/Reading.msg", + "example_messages-1.2.3/pyproject.toml", + ] + assert not (tmp_path / "build").exists() + + +def test_version_change_invalidates_generated_metadata(tmp_path): + config, _ = project(tmp_path) + output = prepare(config) + path = tmp_path / "pyproject.toml" + path.write_text(path.read_text().replace('"1.2.3"', '"1.2.4"')) + prepare(Project.load(tmp_path)) + assert json.loads((output / "message-package.json").read_text())["version"] == "1.2.4" + + +def test_source_archive_is_reproducible(tmp_path, monkeypatch): + project(tmp_path) + monkeypatch.chdir(tmp_path) + first = build_sdist(str(tmp_path / "first")) + second = build_sdist(str(tmp_path / "second")) + assert (tmp_path / "first" / first).read_bytes() == (tmp_path / "second" / second).read_bytes() + + +def test_module_override_cannot_change_distribution_identity(tmp_path): + project(tmp_path) + with (tmp_path / "pyproject.toml").open("a") as stream: + stream.write('python-module = "unrelated"\n') + with pytest.raises(ValueError, match="normalized project name"): + Project.load(tmp_path) + + +def test_transitive_dependencies_are_discovered_and_versions_checked(tmp_path, monkeypatch): + config, _ = project(tmp_path) + base = tmp_path / "base_schemas/package" + generate( + list(schema_roots()), + base, + ["std_msgs/msg/Header"], + "base", + version="1.0.0", + shared=True, + installed=True, + ) + middle = tmp_path / "middle_schemas/package" + middle.mkdir(parents=True) + metadata = json.loads((base / "message-package.json").read_text()) + metadata.update(module="middle", owned=[], dependencies={"base": "1.0.0"}, codec_owner="base") + (middle / "message-package.json").write_text(json.dumps(metadata)) + monkeypatch.setattr( + project_module, + "find_spec", + lambda name: SimpleNamespace(origin=str(tmp_path / name / "__init__.py")), + ) + config.dependency_specs["middle"] = {"version": "1.0.0"} + assert [dep.module for dep in config.dependencies()] == ["base", "middle"] + config.dependency_specs["base"] = {"version": "2.0.0"} + with pytest.raises(ValueError, match="mismatch|Conflicting package versions"): + config.dependencies() + + +def test_python_only_build_needs_no_native_build_tool(tmp_path, monkeypatch): + config, _ = project(tmp_path) + monkeypatch.setattr("dimos_message_project.build.shutil.which", lambda tool: None) + artifacts = build_project(config) + assert artifacts["python_wheel"].endswith("-py3-none-any.whl") + assert (tmp_path / "dist/example_messages-1.2.3.tar.gz").is_file() + assert "cmake_prefix" not in artifacts + assert "cargo_manifest" not in artifacts + + +def test_generator_version_invalidates_project_cache(tmp_path, monkeypatch): + config, _ = project(tmp_path) + output = prepare(config) + state = (output / "generation.json").read_bytes() + monkeypatch.setattr(project_module, "version", lambda _: "0.1.1") + prepare(config) + assert (output / "generation.json").read_bytes() != state + + +def test_rust_build_recovers_dependency_sources_from_python_only_package(tmp_path, monkeypatch): + config, source = project(tmp_path, "std_msgs/Header header\nfloat64 value\n") + dependency = tmp_path / "base_schemas/package" + generate( + list(schema_roots()), + dependency, + ["std_msgs/msg/Header"], + "base", + version="1.0.0", + shared=True, + languages=("python",), + installed=True, + ) + config.dependency_specs["base"] = {"version": "1.0.0", "path": str(dependency)} + commands = [] + monkeypatch.setattr("dimos_message_project.build.shutil.which", lambda tool: "/tools/" + tool) + monkeypatch.setattr(subprocess, "run", lambda command, **kwargs: commands.append(command)) + + artifacts = build_project(config, ("rust",), offline=True) + + manifest = Path(artifacts["cargo_manifest"]) + base = manifest.parent.parent / "base" + assert not (dependency / "rust").exists() + assert (base / "interfaces/std_msgs/msg/Header.msg").read_text() == ( + dependency / "schemas/std_msgs/msg/Header.msg" + ).read_text() + assert "pub use base_messages::std_msgs;" in (manifest.parent / "src/lib.rs").read_text() + assert 'path = "../base"' in manifest.read_text() + schemas = json.loads((manifest.parent / "schemas.json").read_text()) + assert "MSG: std_msgs/Header" in schemas["example_msgs/msg/Reading"] + assert commands == [["cargo", "build", "--manifest-path", str(manifest), "--offline"]] + with tarfile.open(artifacts["cargo_archive"]) as archive: + assert "./base/interfaces/std_msgs/msg/Header.msg" in archive.getnames() + + +def test_selected_language_cache_invalidates_on_selection_edit_delete_and_rename( + tmp_path, monkeypatch +): + (tmp_path / "pyproject.toml").write_text( + '[project]\nname="accept-messages"\nversion="0.1.0"\n[tool.dimos.messages]\ndependencies={}\n' + ) + source = tmp_path / "interfaces/accept_msgs/msg/Reading.msg" + source.parent.mkdir(parents=True) + source.write_text("float64 value\n") + config = Project.load(tmp_path) + + def no_tools(*args, **kwargs): + raise AssertionError("Source packaging invoked an external build") + + monkeypatch.setattr(subprocess, "run", no_tools) + output = prepare(config) + stamp = (output / "generation.json").stat().st_mtime_ns + assert prepare(config) == output + assert (output / "generation.json").stat().st_mtime_ns == stamp + assert not (output / "cpp").exists() + assert not (output / "rust").exists() + prepare(config, ("rust",)) + assert (output / "rust/build.rs").is_file() + assert not (output / "python").exists() + source.rename(source.with_name("Renamed.msg")) + source.with_name("Renamed.msg").write_text("int32 other\n") + prepare(config) + assert not (output / "schemas/accept_msgs/msg/Reading.msg").exists() + assert (output / "schemas/accept_msgs/msg/Renamed.msg").read_text() == "int32 other\n" + source.with_name("Renamed.msg").unlink() + with pytest.raises(ValueError, match="No messages"): + prepare(config) + assert (output / "schemas/accept_msgs/msg/Renamed.msg").is_file() diff --git a/dimos/message_codegen/test_project_install.py b/dimos/message_codegen/test_project_install.py new file mode 100644 index 00000000000..e954f66f77f --- /dev/null +++ b/dimos/message_codegen/test_project_install.py @@ -0,0 +1,126 @@ +# Copyright 2026 Dimensional Inc. +# +# 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. + +import os +from pathlib import Path +import subprocess +import sys +import tarfile + +import pytest + + +def test_clean_source_wheel_sdist_and_editable_install(tmp_path): + wheelhouse = os.environ.get("DIMOS_MESSAGE_WHEELHOUSE") + if not wheelhouse: + pytest.skip("Set DIMOS_MESSAGE_WHEELHOUSE for isolated install acceptance") + wheelhouse = str(Path(wheelhouse).resolve()) + environment = {key: value for key, value in os.environ.items() if key != "PYTHONPATH"} + environment.update( + PIP_NO_INDEX="1", PIP_FIND_LINKS=wheelhouse, CC="/bin/false", CXX="/bin/false" + ) + tools = tmp_path / "tools" + tools.mkdir() + for name in ("cargo", "rustc", "cmake", "c++"): + executable = tools / name + executable.write_text("#!/bin/sh\nexit 97\n") + executable.chmod(0o755) + environment["PATH"] = str(tools) + os.pathsep + environment["PATH"] + venv = tmp_path / "venv" + subprocess.run([sys.executable, "-m", "venv", str(venv)], check=True) + python = str(venv / "bin/python") + app = tmp_path / "app" + definition = app / "interfaces/story_msgs/msg/DeviceReading.msg" + definition.parent.mkdir(parents=True) + definition.write_text("std_msgs/Header header\nfloat64 value\n") + (app / "pyproject.toml").write_text("""[build-system] +requires = ["dimos-message-project==0.1.0"] +build-backend = "dimos_message_project.backend" +[project] +name = "story-messages" +version = "0.1.0" +[tool.dimos.messages] +languages = ["python", "cpp", "rust"] +""") + + def pip(*args): + subprocess.run([python, "-m", "pip", *args], cwd=tmp_path, env=environment, check=True) + + def verify(code): + subprocess.run([python, "-I", "-c", code], cwd=tmp_path, env=environment, check=True) + + header_import = ( + "from dimos_generated.std_msgs.msg import Header; " + "from dimos_generated.builtin_interfaces.msg import Time; " + "header = Header(stamp=Time(sec=0, nanosec=0), frame_id='sensor'); " + ) + pip("install", str(app)) + verify(""" +from importlib.metadata import distributions +from dimos_generated.std_msgs.msg import Header +from dimos_generated.builtin_interfaces.msg import Time +from dimos_cdrgen.registry import encode, decode +from story_messages.story_msgs.msg import DeviceReading +message = DeviceReading(header=Header(stamp=Time(sec=0, nanosec=0), frame_id='sensor'), value=20.5) +assert type(message.header) is Header +assert decode(encode(message), DeviceReading).value == 20.5 +assert 'dimos' not in {dist.metadata['Name'] for dist in distributions()} +""") + assert not list((app / "build").rglob("target")) + # Produce a wheel, then prove its install needs no compiler or backend. + dist = tmp_path / "dist" + pip("wheel", "--no-deps", "--wheel-dir", str(dist), str(app)) + pip("uninstall", "-y", "story-messages") + wheel = next(dist.glob("story_messages-*.whl")) + old_path = environment["PATH"] + environment["PATH"] = str(venv / "bin") + pip("install", "--only-binary=:all:", str(wheel)) + verify( + header_import + + "from story_messages.story_msgs.msg import DeviceReading; assert DeviceReading(header=header, value=7).value == 7" + ) + environment["PATH"] = old_path + # Source distribution builds outside the original project and has no generated output. + pip("install", "dimos-message-project==0.1.0") + subprocess.run( + [ + python, + "-c", + "from dimos_message_project.backend import build_sdist; build_sdist('../sdist')", + ], + cwd=app, + env=environment, + check=True, + ) + source = next((tmp_path / "sdist").glob("*.tar.gz")) + with tarfile.open(source) as archive: + assert not any("/build/" in name for name in archive.getnames()) + pip("install", "--force-reinstall", str(source)) + verify( + header_import + + "from story_messages.story_msgs.msg import DeviceReading; assert DeviceReading(header=header, value=8).value == 8" + ) + pip("install", "-e", str(app)) + definition.write_text(definition.read_text() + 'string unit "C"\n') + pip("install", "-e", str(app)) + verify( + header_import + + "from story_messages.story_msgs.msg import DeviceReading; assert DeviceReading(header=header, value=0., unit='C').unit == 'C'" + ) + definition.rename(definition.with_name("RenamedReading.msg")) + pip("install", "-e", str(app)) + verify( + header_import + + "import story_messages.story_msgs.msg as m; assert not hasattr(m, 'DeviceReading'); assert m.RenamedReading(header=header, value=0., unit='C').unit == 'C'" + ) diff --git a/dimos/message_codegen/test_region_native.py b/dimos/message_codegen/test_region_native.py new file mode 100644 index 00000000000..f88591b7932 --- /dev/null +++ b/dimos/message_codegen/test_region_native.py @@ -0,0 +1,181 @@ +# Copyright 2026 Dimensional Inc. +# +# 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. + +"""Compiled region contracts preserve IDs, cylinder bounds and independent edges.""" + +import json +import os +from pathlib import Path +import subprocess +import sys + +from dimos_cdrgen.generate import generate +from dimos_cdrgen.native_build import prepare_cpp +from dimos_cdrgen.registry import schema_roots +import pytest + +from dimos.message_codegen.native_build import write_cmake_toolchain + + +def test_region_cdr_exchange_through_cpp_and_rust(tmp_path): + if os.environ.get("DIMOS_NATIVE_ACCEPTANCE") != "1": + pytest.skip("Set DIMOS_NATIVE_ACCEPTANCE=1 for compiled region acceptance") + root = Path(__file__).resolve().parents[2] + package = tmp_path / "package" + generate( + list(schema_roots()), + package, + [ + "dimos_msgs/msg/RegionBounds", + "dimos_msgs/msg/RegionPointCloud2", + "dimos_msgs/msg/RegionLineSegments3D", + "dimos_msgs/msg/Contacts", + ], + "region_messages", + shared=True, + ) + sources = { + name: Path(path) + for name, path in json.loads(os.environ.get("DIMOS_NATIVE_SOURCE_DIRS", "{}")).items() + } + cache = os.environ.get("DIMOS_NATIVE_TEST_CACHE") + prefix = prepare_cpp( + package, + cache=Path(cache) if cache else None, + offline=os.environ.get("DIMOS_OFFLINE") == "1", + source_dirs=sources or None, + ) + toolchain = write_cmake_toolchain(prefix, tmp_path / "toolchain.cmake") + (tmp_path / "dimos_message_project").symlink_to(Path(__file__).parent, target_is_directory=True) + env = {**os.environ, "PYTHONPATH": os.pathsep.join([str(tmp_path), str(package / "python")])} + bootstrap = """ +from pathlib import Path +from dimos_cdrgen import registry +registry.providers = lambda: () +registry.initialize((Path('package'),), discover=False) +from region_messages.dimos_msgs.msg import RegionBounds, RegionPointCloud2, RegionLineSegments3D, LineSegments3D, LineSegment3D +from region_messages.geometry_msgs.msg import Point +from region_messages.sensor_msgs.msg import PointCloud2 +from region_messages.std_msgs.msg import Header +from region_messages.builtin_interfaces.msg import Time +import numpy as np +header = Header(stamp=Time(sec=12, nanosec=34), frame_id='map') +values = [ + RegionBounds(header=header, region_id=-196603, center=Point(x=-3.,y=5.,z=0.), radius=2.5,z_min=-1.,z_max=4.), + RegionPointCloud2(region_id=-196603,cloud=PointCloud2(header=header,height=1,width=0,fields=[],is_bigendian=False,point_step=12,row_step=0,data=np.empty(0,dtype=np.uint8),is_dense=True)), + RegionLineSegments3D(region_id=-196603,lines=LineSegments3D(header=header,segments=[ + LineSegment3D(start=Point(x=1.,y=2.,z=3.),end=Point(x=4.,y=5.,z=6.),weight=0.5), + LineSegment3D(start=Point(x=9.,y=8.,z=7.),end=Point(x=6.,y=5.,z=4.),weight=100.)]))] +""" + subprocess.run( + [ + sys.executable, + "-c", + bootstrap + + "\nfor i,value in enumerate(values): Path(f'input{i}.cdr').write_bytes(registry.encode(value))", + ], + cwd=tmp_path, + env=env, + check=True, + ) + consumer = tmp_path / "consumer" + consumer.mkdir() + (consumer / "CMakeLists.txt").write_text(f"""cmake_minimum_required(VERSION 3.20) +project(region_consumer LANGUAGES CXX) +find_package(region_messages CONFIG REQUIRED) +add_executable(consumer main.cpp) +target_compile_features(consumer PRIVATE cxx_std_17) +target_include_directories(consumer PRIVATE "{root}/native/cpp/include") +target_link_libraries(consumer PRIVATE region_messages::messages) +""") + (consumer / "main.cpp").write_text("""#include +#include +#include +#include +#include +#include +#include +template T read(int i) { + std::ifstream file("input"+std::to_string(i)+".cdr",std::ios::binary); + std::vector bytes((std::istreambuf_iterator(file)),{}); + auto value=dimos::native::cdr_decode(bytes); + if(value.region_id!=-196603) throw std::runtime_error("region ID lost"); + auto wire=dimos::native::cdr_encode(value); + std::ofstream output("cpp"+std::to_string(i)+".cdr",std::ios::binary); + output.write(reinterpret_cast(wire.data()),wire.size()); + return value; +} +int main() { + auto bounds=read(0); + if(bounds.center.x!=-3 || bounds.radius!=2.5 || bounds.z_min!=-1 || bounds.z_max!=4) return 1; + auto cloud=read(1); + if(cloud.cloud.width!=0 || cloud.cloud.header.frame_id!="map") return 2; + auto edges=read(2); + if(edges.lines.segments.size()!=2 || edges.lines.segments[1].start.x!=9 || edges.lines.segments[1].weight!=100) return 3; +} +""") + subprocess.run( + [ + "cmake", + "-S", + str(consumer), + "-B", + str(tmp_path / "cpp"), + f"-DCMAKE_TOOLCHAIN_FILE={toolchain}", + ], + check=True, + ) + subprocess.run(["cmake", "--build", str(tmp_path / "cpp"), "--parallel", "2"], check=True) + subprocess.run([str(tmp_path / "cpp/consumer")], cwd=tmp_path, check=True) + binary = package / "rust/src/bin" + binary.mkdir() + ( + binary / "exchange.rs" + ).write_text("""use region_messages_messages::dimos_msgs::msg::{region_bounds::RegionBounds,region_point_cloud2::RegionPointCloud2,region_line_segments3_d::RegionLineSegments3D}; +fn main() { + for i in 0..3 { + let wire=std::fs::read(format!("cpp{i}.cdr")).unwrap(); + let body=match i { + 0=>{let (v,n)=re_cdr::from_bytes::(&wire[4..]).unwrap(); assert_eq!(n,wire.len()-4);assert_eq!((v.region_id,v.center.x,v.radius,v.z_min,v.z_max),(-196603,-3.,2.5,-1.,4.)); re_cdr::to_vec::<_,re_cdr::LittleEndian>(&v).unwrap()}, + 1=>{let (v,n)=re_cdr::from_bytes::(&wire[4..]).unwrap();assert_eq!(n,wire.len()-4);assert_eq!(v.region_id,-196603);assert_eq!(v.cloud.header.frame_id,"map");assert_eq!(v.cloud.width,0); re_cdr::to_vec::<_,re_cdr::LittleEndian>(&v).unwrap()}, + _=>{let (v,n)=re_cdr::from_bytes::(&wire[4..]).unwrap();assert_eq!(n,wire.len()-4);assert_eq!(v.region_id,-196603);assert_eq!(v.lines.segments.len(),2);assert_eq!((v.lines.segments[1].start.x,v.lines.segments[1].weight),(9.,100.));re_cdr::to_vec::<_,re_cdr::LittleEndian>(&v).unwrap()} + }; + let mut output=vec![0,1,0,0];output.extend(body);std::fs::write(format!("rust{i}.cdr"),output).unwrap(); + } +} +""") + subprocess.run( + [ + "cargo", + "run", + *(["--offline"] if os.environ.get("DIMOS_OFFLINE") == "1" else []), + "--manifest-path", + str(package / "rust/Cargo.toml"), + "--bin", + "exchange", + ], + cwd=tmp_path, + check=True, + ) + subprocess.run( + [ + sys.executable, + "-c", + bootstrap + + "\nfor i,value in enumerate(values): assert registry.encode(registry.decode(Path(f'rust{i}.cdr').read_bytes(),type(value))) == registry.encode(value)", + ], + cwd=tmp_path, + env=env, + check=True, + ) diff --git a/dimos/message_codegen/test_repository_tutorial.py b/dimos/message_codegen/test_repository_tutorial.py new file mode 100644 index 00000000000..f8f997281e1 --- /dev/null +++ b/dimos/message_codegen/test_repository_tutorial.py @@ -0,0 +1,177 @@ +# Copyright 2026 Dimensional Inc. +# +# 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. + +import json +import os +from pathlib import Path +import re +import shutil +import subprocess +import sys + +import pytest + +try: + import tomllib +except ModuleNotFoundError: # Python 3.10 + import tomli as tomllib + + +def test_builtin_tutorial_builds_new_definition_without_runtime(tmp_path): + wheelhouse = os.environ.get("DIMOS_MESSAGE_WHEELHOUSE") + if not wheelhouse: + pytest.skip("Set message wheelhouse for clean source acceptance") + root = Path(__file__).resolve().parents[2] + tutorial = (root / "docs/development/messages-in-repository.md").read_text() + definition = re.search(r"\n```text\n(.*?)```", tutorial, re.S) + check = re.search(r"\n```python skip\n(.*?)```", tutorial, re.S) + assert definition is not None and check is not None + checkout = tmp_path / "checkout" + ignore = shutil.ignore_patterns("build", "dist", "*.egg-info", "__pycache__", "target") + shutil.copytree( + root / "dimos/message_codegen", checkout / "dimos/message_codegen", ignore=ignore + ) + (checkout / "dimos/__init__.py").write_text("") + package = checkout / "packages/dimos-generated" + shutil.copytree(root / "packages/dimos-generated", package, ignore=ignore) + source = checkout / "packages/dimos-generated/interfaces/dimos_msgs/msg/DeviceReading.msg" + assert not source.exists() + source.write_text(definition.group(1)) + catalog = package / "catalog.json" + roots = json.loads(catalog.read_text()) + roots["roots"]["dimos_msgs/msg/DeviceReading"] = "Repository tutorial contract" + catalog.write_text(json.dumps(roots)) + environment = {key: value for key, value in os.environ.items() if key != "PYTHONPATH"} + environment.update( + PATH=os.pathsep.join( + directory + for directory in os.environ["PATH"].split(os.pathsep) + if Path(directory) != Path(sys.executable).parent + ), + PIP_NO_INDEX="1", + PIP_FIND_LINKS=str(Path(wheelhouse).resolve()), + CC="/bin/false", + CXX="/bin/false", + ) + (checkout / "scripts").mkdir() + shutil.copyfile( + root / "scripts/generate_builtin_messages.py", + checkout / "scripts/generate_builtin_messages.py", + ) + shutil.copyfile(root / "pyproject.toml", checkout / "pyproject.toml") + subprocess.run( + [sys.executable, "-m", "scripts.generate_builtin_messages"], + check=True, + cwd=checkout, + env=environment, + ) + venv = tmp_path / "venv" + subprocess.run([sys.executable, "-m", "venv", str(venv)], check=True) + python = str(venv / "bin/python") + dist = tmp_path / "dist" + uv = shutil.which("uv") + assert uv is not None, "Prepare uv before running the repository tutorial" + subprocess.run( + [ + uv, + "build", + str(package), + "--python", + python, + "--out-dir", + str(dist), + "--no-index", + "--find-links", + str(Path(wheelhouse).resolve()), + ], + cwd=tmp_path, + env=environment, + check=True, + ) + wheel = next(dist.glob("dimos_generated-*.whl")) + subprocess.run( + [python, "-m", "pip", "install", str(wheel)], + cwd=tmp_path, + env=environment, + check=True, + ) + validation = ( + check.group(1) + + """ +from importlib.metadata import distributions +assert 'dimos' not in {dist.metadata['Name'] for dist in distributions()} +from dimos_cdrgen.registry import schema +assert 'MSG: std_msgs/Header' in schema(DeviceReading.__msgtype__) +""" + ) + subprocess.run([python, "-I", "-c", validation], cwd=tmp_path, env=environment, check=True) + + +def test_checkout_sync_sees_generated_source_changes_without_reinstall(tmp_path): + wheelhouse = os.environ.get("DIMOS_MESSAGE_WHEELHOUSE") + if not wheelhouse: + pytest.skip("Set message wheelhouse for clean checkout acceptance") + root = Path(__file__).resolve().parents[2] + config = tomllib.loads((root / "pyproject.toml").read_text()) + source = config["tool"]["uv"]["sources"]["dimos-generated"] + checkout = tmp_path / "checkout" + package = checkout / source["path"] + shutil.copytree( + root / source["path"], + package, + ignore=shutil.ignore_patterns("build", "dist", "*.egg-info", "__pycache__"), + ) + (checkout / "pyproject.toml").write_text( + '[project]\nname = "checkout-probe"\nversion = "0.1.0"\n' + f'requires-python = "=={sys.version_info.major}.{sys.version_info.minor}.*"\n' + 'dependencies = ["dimos-generated==0.1.0"]\n[tool.uv.sources]\n' + f'dimos-generated = {{ path = "{source["path"]}", editable = {str(source.get("editable", False)).lower()} }}\n' + ) + environment = { + key: value + for key, value in os.environ.items() + if key not in {"PYTHONPATH", "VIRTUAL_ENV", "UV_PROJECT_ENVIRONMENT"} + } + environment.update(CC="/bin/false", CXX="/bin/false", UV_PYTHON_DOWNLOADS="never") + uv = shutil.which("uv") + assert uv is not None, "Prepare uv before running checkout acceptance" + subprocess.run( + [ + uv, + "sync", + "--python", + sys.executable, + "--no-index", + "--find-links", + str(Path(wheelhouse).resolve()), + ], + cwd=checkout, + env=environment, + check=True, + ) + python = str(checkout / ".venv/bin/python") + validation = ( + "import dimos_generated; " + "from dimos_generated.geometry_msgs.msg import Point; " + "from dimos_cdrgen.registry import encode, decode; " + "assert decode(encode(Point(x=1.25, y=0., z=0.)), Point).x == 1.25; " + "assert dimos_generated.CHECKOUT_PROBE == 17" + ) + # Editable installation must expose refreshed generated package exports. + # The isolated wheel tutorial above verifies actual .msg -> source generation. + # Native rosbags classes are not declarations in _types.py to rewrite. + exports = package / "build/message-source/python/dimos_generated/__init__.py" + exports.write_text(exports.read_text() + "\nCHECKOUT_PROBE = 17\n") + subprocess.run([uv, "sync", "--frozen", "--offline"], cwd=checkout, env=environment, check=True) + subprocess.run([python, "-I", "-c", validation], cwd=checkout, env=environment, check=True) diff --git a/dimos/simulation/habitat/nix/flake.lock b/dimos/simulation/habitat/nix/flake.lock index b85bc9a050a..5ef7dc7f483 100644 --- a/dimos/simulation/habitat/nix/flake.lock +++ b/dimos/simulation/habitat/nix/flake.lock @@ -11,11 +11,11 @@ }, "locked": { "dir": "native/cpp", - "lastModified": 1792431336, - "narHash": "sha256-W0biIt+6oH7bBHt44kV4J411Y3AUsuMkQ7OsS45BxDE=", + "lastModified": 1792432073, + "narHash": "sha256-5BgFoVp3/X5bKasI5G+f41sqVGAnZ4VPi1w3eC6+DIM=", "owner": "dimensionalOS", "repo": "dimos", - "rev": "fbccb5c45eb84a7f65413a37cba7afe3fe2d8008", + "rev": "ea1d296b163d325d2dea782c4057dbaa3b697fc4", "type": "github" }, "original": { diff --git a/docs/development/message-reference.md b/docs/development/message-reference.md new file mode 100644 index 00000000000..4f02091b17b --- /dev/null +++ b/docs/development/message-reference.md @@ -0,0 +1,117 @@ +# Message contracts + +This reference applies to both built-in and external messages in the CDR +proposal. Definitions are `.msg` files, with identities such as +`dimos_msgs/msg/DeviceReading` or `story_msgs/msg/DeviceReading`. Generation +packages Python imports/stubs and schemas, C++ ROSIDL source projects, and Rust +crate/build-script inputs. Rosbags initializes Python classes/codecs in memory +from installed schemas. CMake and Cargo generate and compile native declarations; +Python installation needs no native compiler. Import performs no native +compilation, filesystem code generation or downloads. No ROS installation is required. CDR/schema compatibility does not mean that +this package builds a ROS node. + +## One owner for a dependency type + +A field declared `std_msgs/Header header` uses the built-in package's Header in +all languages. External packages import the same Python class, C++ declaration +and Rust dependency type instead of creating another identity. Constructors and +field assignment preserve that type. Python dataclasses retain the supplied +Header object; use `copy.deepcopy` for independently mutable nested values. +C++ and Rust retain their native copy/move semantics. Exact dependency versions, definitions and binding ABI must +agree. Conflicting owners or dependencies fail the build. Runtime schema-hash +routing enforcement is not implemented; do not rely on it to detect every +same-name schema mismatch. + +External project defaults discover `interfaces//msg/*.msg` and derive +the Python module name from the distribution name in `pyproject.toml`. +`dimos-message-project` provides the PEP517/660 backend shared with `dimos build`. +`pip install .` in that project builds only Python; `dimos build` builds its +configured language outputs. Build isolation installs declared Python build +dependencies, not OS toolchains or the dimOS runtime. + +## Generated values and runtime modules + +Generated fields follow the `.msg` layout: `header.stamp.sec`/`nanosec`, nested +poses and explicit image dimensions/encoding/data. Python values expose +`__msgtype__`; registry functions supply codecs and complete schemas: + +```python +from dimos_generated.geometry_msgs.msg import Vector3 +from dimos_cdrgen.registry import encode, decode, schema + +message = Vector3(x=1.0, y=2.0, z=3.0) +assert decode(encode(message), Vector3) == message +assert "float64 x" in schema(message.__msgtype__) +``` + +Python and Rust constructors require all fields explicitly, including fields +with `.msg` defaults. Python numeric array fields require the declared NumPy dtype. Normal modules publish and receive typed values through SDK ports rather +than manually encoding bytes. Math, image/cloud conversion and visualization +helpers live outside the generated value classes. + +The runtime SDK supplies Python `Module` with `In`/`Out`, C++ +`Module`/`Builder`/`Output` and Rust `Module`/`Input`/`Output` with CDR +adapters. These runtime APIs belong to the runtime-cutover layer; standalone +message builds do not install the complete native SDK. LCM and Zenoh remain +transports: CDR replaces typed encoding. + +## Distribution and recordings + +CI distributes built-in Python wheels/sdists, C++ source packages and Rust crates. +Python users install matching wheels without building dimOS. C++ source consumers +prepare the pinned upstream support libraries explicitly; prebuilt native SDK +products are out of scope. External authors distribute their wheel/sdist, native +source archive and Cargo crate with matching dependency versions. Current proposal packages are review +artifacts, not an assumed public-index release. Pip does not honor a checkout's +`[tool.uv.sources]`; provide matching distributions explicitly. + +Providers export owned types and the complete dependency schema closure. MCAP +embeds CDR bytes and full `ros2msg` schemas even when dependency value types are +imported from another package. Viewers need no installed custom package; typed +replay needs matching installed types. Known native stamped layouts preserve +source time. Unknown external native layouts currently use reception time while +retaining the complete payload Header. + +Changing a wire layout requires matching rebuilt packages. The proposal is a +deliberate old-message API/wire break; transparent legacy-recording decoding and +mixed old/new typed deployments are not supported. + +CDR input must be trusted and schema-matched. Native libraries do not uniformly +reject malformed bytes or enforce every bound; unsupported bounded Python schemas +raise `NotImplementedError`. The [accepted limitations](https://tomcc7.github.io/dimos-cdrgen/) +list precise strict expected failures. Do not use this decoder as a hostile-input +validation boundary. + +Rust packages contain owned `.msg` inputs, a small `build.rs` adapter and the +codec/schema contracts. Normal `cargo build` invokes pinned `ros2msg` to generate +the declarations in Cargo's `OUT_DIR`; `src/lib.rs` includes that result. This +also applies to the Rust part of `dimos build`. Cargo and its dependency cache +are native build prerequisites, not Python installation prerequisites. No helper +binary, ROS installation or runtime download is required. Dependency types are +reexported from their owner crate, preserving exact cross-package identity. + +## Region and simulator metadata + +Ordinary image, cloud, pose, path, camera, TF and IMU streams retain their ROS2 +schemas. The planner's region streams use explicit custom envelopes: + +- `RegionPointCloud2`: signed `int32 region_id` plus a standard `cloud`. +- `RegionBounds`: `header`, signed `region_id`, `center`, `radius`, `z_min`, `z_max`. +- `RegionLineSegments3D`: signed `region_id` plus `lines`; every segment has its + own `start`, `end` and `weight`. + +Seed cloud and bounds pair on `region_id`, including regions with the same +source timestamp. Viewer cell IDs pack two signed 16-bit coordinates into the +signed 32-bit ID. Replacement and empty messages retain the same ID. Cloud and +line envelopes carry source clock/frame metadata in `cloud.header` and +`lines.header`; bounds carry their own header. MCAP's unsigned message sequence +is transport metadata and is separate from the signed region ID. + +`Contacts` carries a Header and `Contact[]` with semantic `part`/`kind` labels. +The simulator emits trunk/lidar/leg/foot and floor/wall/ceiling/clutter labels. +It replaces the former JSON-in-String contact wire encoding. Generated values +remain ordinary value types; semantic helpers live outside them. + +Rerun's region adapters render these envelopes. Foxglove can read their embedded +schemas and raw fields, but custom region 3D visualization is currently unsupported; +this proposal does not add a Foxglove plugin or duplicate visualization streams. diff --git a/docs/development/messages-external-project.md b/docs/development/messages-external-project.md new file mode 100644 index 00000000000..12c622bf53b --- /dev/null +++ b/docs/development/messages-external-project.md @@ -0,0 +1,446 @@ +# Use installed dimOS with a custom message project + +There are two workflows. dimOS's built-in messages are built in CI and arrive as +prebuilt packages with dimOS. Ordinary users install and import them; they do not +run a generator. `dimos build` is for authors of **external custom messages**. +It builds that message project, not the robot runtime. `dimos bake` remains the +separate command for composing Rust native modules into a host executable. + +These packages currently belong to the CDR proposal, not a released main-branch +API. Use matching review wheels for `dimos`, `dimos-generated` and +`dimos-message-project`; `PIP_FIND_LINKS` can point pip at that wheel directory. +Do not assume these proposal versions are available on a public package index. +The `message-authoring-packages` CI artifact also contains matching built-in +native source inputs (`dimos-messages-sources-0.1.0.tar.gz`) and a Rust crate +(`dimos-generated-messages-0.1.0.crate`). These use the message package's version, +independently of the dimOS runtime version. The C++ archive is **not a prebuilt +SDK**: the shared native build core still generates and compiles ROSIDL typesupport +and its pinned support libraries. C++ distribution is source-only in this proposal; +prebuilt native SDK archives are out of scope. Python wheel installation does not +perform this native build. + +Read the [accepted native-library limitations](https://tomcc7.github.io/dimos-cdrgen/) before using +these packages: malformed inputs may be accepted and bounded Python messages are +unsupported. These provisional non-blockers are not proof of parser safety. + +## Prepare matching review packages + +Start in your own project directory, outside the dimOS checkout. This workflow +requires the complete runtime-cutover proposal. Download **matching HEAD** review +artifacts from the draft stack's Actions runs; these packages are not assumed to +exist on PyPI. The nonpublishing wheel matrix uploads `checked-wheels--`; +choose exactly one compatible runtime wheel and built-in wheel for your Python +and platform. `checked-message-backend` supplies the backend wheel. Put those +three wheels in `review/wheels/`, then: + +```sh skip +python -m venv .venv +. .venv/bin/activate +export PIP_FIND_LINKS="$(realpath review/wheels)" +pip install review/wheels/dimos-*.whl review/wheels/dimos_generated-*.whl \ + review/wheels/dimos_message_project-*.whl +``` + +Pip installs their declared dependencies. An offline installation additionally +needs those dependency wheels in a prepared wheelhouse and `--no-index`. +Direct wheel filenames select the proposal builds; an unqualified `pip install +dimos` may select a released package with a different API. Pip does not consult +`[tool.uv.sources]` from a dimOS checkout. + +Python message source builds generate ordinary Python classes and use setuptools; +they require no C++ compiler, Python development headers, CMake or Fast CDR. +Installed messages use NumPy and pinned rosbags 0.11.0 for CDR. A three-language +application additionally needs CMake, Rust/Cargo, Fast CDR and the native SDK. +The currently verified coordinator example runs on Linux x86_64. + +## Prepare native consumers once + +The main CI run's `external-message-project` artifact contains both +`examples/message-project/sdk/` (Rust SDK sources) and `build/native-sdk/` (the +installed C++ SDK). Download it from the same HEAD as your packages: + +```sh skip +gh run download "$NATIVE_RUN" --repo dimensionalOS/dimos \ + --name external-message-project --dir review/native +cp -R review/native/examples/message-project/sdk . +``` + +Set `NATIVE_RUN` to that verified successful main-CI run ID. GitHub artifact access +requires your existing account access; no credentials are created by this +workflow. Native C++ additionally requires Fast CDR 2.4.0, Zenoh C/C++ >=1.9.0 +with unstable API enabled, raw LCM development files discoverable by pkg-config, +and threads support. PFR/JSON headers are included in the installed SDK. Prepare +those dependencies explicitly; the message wheel does not provide them. + +With `FASTCDR_PREFIX`, `ZENOHC_PREFIX` and `ZENOHCXX_PREFIX` set to those prepared +installations, configure the environment: + +```sh skip +export CMAKE_PREFIX_PATH="$(realpath review/native/build/native-sdk):$FASTCDR_PREFIX:$ZENOHC_PREFIX:$ZENOHCXX_PREFIX" +pkg-config --exists lcm +``` + +For libraries outside default loader locations, also configure your environment's +library search paths. Cargo dependencies must be cached before `--offline` works. +The SDK does not hide these toolchain contracts or install OS packages. + +## Define one message + +Create `interfaces/story_msgs/msg/DeviceReading.msg`: + + +```text +std_msgs/Header header +uint32 sequence +float64 value +string label "sensor" +``` + +The directory supplies the identity `story_msgs/msg/DeviceReading`. `Header` +comes from the built-in package. The custom package imports that existing type +in all three languages; it does not regenerate another Header. + +Add `pyproject.toml` once: + + +```toml +[build-system] +requires = ["dimos-message-project==0.1.0"] +build-backend = "dimos_message_project.backend" + +[project] +name = "story-messages" +version = "0.1.0" + +[tool.dimos.messages] +languages = ["python", "cpp", "rust"] +``` + +The module name defaults to `story_messages`, derived from the project name. +All `.msg` files under `interfaces//msg/` are discovered automatically. +The default dependency is the compatible `dimos_generated` message package at +version `0.1.0`; additional packages require explicit exact versions under +`[tool.dimos.messages.dependencies]`. Conflicting owners, definitions, versions +or binding ABIs are errors. Runtime never downloads schemas or invokes a native toolchain. On first use, +rosbags initializes native Python classes/codecs in memory from the installed +schemas; there is no generated-file write or constructor/class postprocessing. + +## Build or install + +For a Python source checkout, this is sufficient: + +```sh skip +pip install . +``` + +The normal PEP 517 backend generates and packages Python source only, even when +the project lists C++ and Rust. Build isolation installs the lightweight backend, +setuptools/wheel and pinned message dependencies; it does not install dimOS or +build the robot runtime. No message-native compiler is needed. Python installation +resolves NumPy and rosbags dependencies normally; it performs no OS installation +or native compilation at import. Rosbags initializes its Python classes/codecs +in memory from the installed schemas. + +To build all configured language artifacts instead of installing Python: + +```sh skip +dimos build +``` + +Outputs go to `dist/`, with local generated/build files in `build/dimos/`. +`build/dimos/artifacts.json` records the wheel, CMake prefix, Cargo manifest and +schema paths. Unchanged generation inputs are reused; edited, deleted and renamed +messages invalidate the generated package. CMake and Cargo perform native builds. + +```sh skip +dimos build --language cpp # select one output language +dimos build --install # also install Python into the active virtualenv +dimos build --offline # require cached native sources and Cargo dependencies +``` + +Use pip's `--no-index --find-links` with a prepared wheelhouse for offline Python +builds. C++ message source preparation supports Linux and macOS and requires a C/C++ +compiler, CMake and `dimos-message-project[native]` in the active environment. +It builds pinned upstream ROSIDL/FastRTPS/Fast CDR support in a writable local +cache; it does not install ROS system packages. The first online native build +fetches those explicitly selected source dependencies; `--offline` fails if they +are absent. Rust selection requires Cargo and its dependency cache. Python-only builds need neither native +toolchain. Missing prerequisites fail clearly without installing system tools. + +Editable installation is also supported: + +```sh skip +pip install -e . +# After changing a .msg, rebuild explicitly, then restart running Python processes: +pip install -e . +``` + +An editable install is not import-time compilation or native-code hot reload. +Consumers installing a matching wheel need no compiler: + +```sh skip +pip install --only-binary=:all: dist/story_messages-*.whl +``` + +## Python: a real module input and output + +`demo_modules.py` receives `raw`, adds one, and publishes `reading`: + + +```python skip +from story_messages.story_msgs.msg import DeviceReading + +from dimos.core.module import Module +from dimos.core.stream import In, Out + + +class ReadingProcessor(Module): + raw: In[DeviceReading] + reading: Out[DeviceReading] + + async def handle_raw(self, message: DeviceReading) -> None: + self.reading.publish( + DeviceReading( + header=message.header, + sequence=message.sequence, + value=message.value + 1, + label=message.label, + ) + ) +``` + +Automatic `handle_` handlers are **async**. No manual CDR calls or +`PYTHONPATH` changes are required after installation. These are native rosbags +dataclasses: this constructor reuses the Header object and its dependency-owned +Python type. It changes only the new reading's value. Use `copy.deepcopy` when +your module needs an independently mutable nested message. Python and Rust +constructors require every field explicitly; `.msg` defaults are not injected. +Numeric Python array fields use NumPy arrays with the declared dtype. + +## C++: use the installed message and SDK packages + +`cpp/processor.cpp` receives `reading` and publishes `processed`: + + +```cpp +#include +#include + +using namespace dimos::native; +using Reading = story_msgs::msg::DeviceReading; + +class Processor : public Module { + Output processed_; +public: + void build(Builder& builder, Config&) override { + processed_ = builder.output("processed"); + builder.input("reading", &Processor::process, this); + } + void process(const Reading& input) { + auto output = input; + output.value += 1; + processed_.publish(output); + } +}; + +int main() { run_with_transport(); } +``` + +The consumer's CMake file declares packages, not generated include paths: + + +```cmake +cmake_minimum_required(VERSION 3.20) +project(reading_processor LANGUAGES CXX) +find_package(dimos_native CONFIG REQUIRED) +find_package(story_messages CONFIG REQUIRED) +add_executable(processor processor.cpp) +target_link_libraries(processor PRIVATE dimos_native::dimos_native story_messages::messages) +``` + +Prepare the SDK and its pinned Zenoh/raw-LCM dependencies once. Its installation +exports `dimos_native::dimos_native` and propagates required includes/libraries. +`dimos build` emits a CMake toolchain file locating this project's message package +and its dependencies, including the Python resources used by upstream ament +CMake configuration. This file contains absolute local paths; rerun `dimos build` +after moving the environment. The example's standard CMake preset uses that file: + + +```json +{ + "version": 3, + "configurePresets": [ + { + "name": "dimos", + "generator": "Unix Makefiles", + "binaryDir": "${sourceDir}/../build/cpp", + "toolchainFile": "${sourceDir}/../build/dimos/toolchain.cmake" + } + ], + "buildPresets": [ + { + "name": "dimos", + "configurePreset": "dimos", + "jobs": 2 + } + ] +} +``` + +With the SDK/Fast CDR prefixes supplied by your development environment: + +```sh skip +cd cpp +cmake --preset dimos +cmake --build --preset dimos +cd .. +``` + +## Rust: typed SDK ports, not a raw-byte example + +`rust/src/main.rs` receives `processed` and publishes `checked`: + + +```rust +use dimos_module::{Input, Module, Output, cdr, run_with_transport}; +use story_messages_messages::story_msgs::msg::device_reading::DeviceReading; + +#[derive(Module)] +struct Processor { + #[input(decode = cdr::decode)] + processed: Input, + #[output(encode = cdr::encode)] + checked: Output, +} + +impl Processor { + async fn handle_processed(&mut self, mut message: DeviceReading) { + message.value += 1.0; + if let Err(error) = self.checked.publish(&message).await { + tracing::error!(%error, "publish failed"); + } + } +} + +#[tokio::main] +async fn main() { + run_with_transport::().await; +} +``` + +The generated crate shares the built-in package's codec trait, so these SDK +`cdr::encode/decode` adapters accept the custom type directly. Package locations +belong in Cargo configuration, not application source: + + +```toml +[package] +name = "reading-processor" +version = "0.1.0" +edition = "2024" + +[workspace] + +[dependencies] +dimos-module = { path = "../sdk/rust/dimos-module" } +story-messages-messages = { path = "../build/dimos/cargo-packages/story_messages" } +tokio = { version = "1", features = ["rt-multi-thread", "macros"] } +tracing = "0.1" + +[patch.crates-io] +dimos-generated-messages = { path = "../build/dimos/cargo-packages/dimos_generated" } +``` + +Here `sdk/` is an unpacked SDK review artifact. `build/dimos/cargo-packages/` +contains the custom crate and its message dependencies, each with a single owner. +The patch ensures the SDK resolves the same built-in crate as the custom message. +This local source bundle works before registry publication. + +```sh skip +cargo build --manifest-path rust/Cargo.toml --offline +``` + +Rust dependencies must be cached for `--offline`; otherwise perform an explicit +normal Cargo dependency setup first. No ROS installation is required for either +native language. CDR/schema compatibility is not a ROS node build integration. + +## Connect and run the three languages + +Declare the native executables' ports in Python: + +```python skip +from dimos.core.native_module import NativeModule +from dimos.core.stream import In, Out +from story_messages.story_msgs.msg import DeviceReading + +class CppProcessor(NativeModule): + reading: In[DeviceReading] + processed: Out[DeviceReading] + +class RustProcessor(NativeModule): + processed: In[DeviceReading] + checked: Out[DeviceReading] +``` + +The coordinator supplies topics and transport configuration to native workers. +For the finite acceptance example, `Exchange` publishes one input and checks the +reply; the module chain itself uses the normal blueprint API: + +```python skip +from dimos.core.coordination.blueprints import autoconnect + +application = autoconnect( + Exchange.blueprint(), + ReadingProcessor.blueprint(), + CppProcessor.blueprint(executable=str(cpp.resolve()), stdin_config=True), + RustProcessor.blueprint(executable=str(rust.resolve()), stdin_config=True), +) +``` + +The snippets above show the module API. The finite `Exchange` harness is part of +[the complete example](/examples/message-project); copy that example directory +from the same proposal HEAD if you want to run this exact acceptance command. +The message wheel alone does not install the harness, native SDK or CMake consumer +project. After preparing the SDK, building both processors and installing the +custom Python wheel, run from the example directory: + +```sh skip +python demo_blueprint.py --transport zenoh +``` + +It starts a loopback-only Zenoh router, runs actual Python and native workers, +validates the complete returned CDR value, and stops all owned processes: + +```text +PASS: 20.5 -> Python 21.5 -> C++ 22.5 -> Rust 23.5; Header and sequence preserved +``` + +`--transport lcm` uses the same modules on a multicast-configured host. The harness +reports system tuning requirements without applying them. Host multicast and +hardware acceptance remain separate from the offline Zenoh check. + +The source files are in [the complete example](/examples/message-project). +CI checks that the embedded file blocks match those sources, compiles the native +processors and runs the coordinator example. Installation/coordinator blocks use +`skip` in the generic Markdown runner because dedicated isolated/native tests own +their environments and cleanup; they are not substitute pseudocode. + +## Distribute, record and evolve + +Distribute the custom wheel/sdist, CMake archive and Cargo source bundle together +with matching dependency versions. Local installation does not require publishing +to a registry. Standard types retain their original Python class, C++ declaration +and Rust crate identity across package boundaries. + +Message providers export owned types plus the full schema closure. MCAP embeds +`cdr` bytes and complete `ros2msg` schemas, so a viewer does not need your custom +package installed. Typed replay needs the matching package. Source timestamps +remain `header.stamp.sec`/`nanosec`; helpers handle geometry and image operations +outside generated value types. + +Changing a wire layout requires rebuilding and distributing matching packages to +producers and typed consumers. This proposal intentionally breaks the old LCM +message API/wire format. LCM remains a transport; mixed old/new typed deployments +and transparent legacy-recording decoding are not supported. + +For the other workflow, see [built-in development](/docs/development/messages-in-repository.md). Both share [message contracts](/docs/development/message-reference.md). diff --git a/docs/development/messages-in-repository.md b/docs/development/messages-in-repository.md new file mode 100644 index 00000000000..ddf01a34a0d --- /dev/null +++ b/docs/development/messages-in-repository.md @@ -0,0 +1,132 @@ +# Develop a built-in message in the repository + +Use this tutorial when changing dimOS's own message definitions. Work in a +checkout of the CDR proposal; this is not a main-branch or published-release API. +The separate `packages/dimos-generated` package owns checked-in generated Python source. +The root dimOS package consumes it and does not generate it in `setup.py`. + +Prepare Python 3.12 and uv for installation. Message maintainers additionally +need Ruff 0.14.3 and rustfmt for explicit generation. Native applications need +their C++/Rust toolchains. No ROS installation is required. These are explicit toolchain +prerequisites; message builds do not install OS packages. From the checkout root: + +```sh skip +uv sync --group tests --group message-codegen --frozen +``` + +`uv sync` installs the built-in message package as editable Python source from +`packages/dimos-generated/src`; no message-native extension is built. It consumes +the local packages in +`[tool.uv.sources]`. **Plain `pip install .` at the dimOS root does not read those +uv sources.** It needs matching `dimos-generated` and `dimos-message-project` +distributions available to pip; it is not a substitute for this checkout setup. + +The [accepted native-library limitations](https://tomcc7.github.io/dimos-cdrgen/) describe the +provisional input constraints and unsupported schemas. They also identify the +precise expected-failure tests; bounded valid messages do not silently work. + +## Define and rebuild one message + +Create `packages/dimos-generated/custom/dimos_msgs/msg/DeviceReading.msg`: + + +```text +std_msgs/Header header +uint32 sequence +float64 value +string label "sensor" +``` + +The directory supplies `dimos_msgs/msg/DeviceReading`. The vendored `.msg` is the +source of truth; do not edit generated bindings. Standard message inputs are +vendored separately and intentionally pinned; avoid editing a standard Header +just to add an application-specific field. + +Generate source explicitly after editing `.msg`: + +```sh skip +uv run python -m scripts.generate_builtin_messages +uv run python -m scripts.generate_builtin_messages --check +``` + +The checkout's editable dependency uses the regenerated source directly; no +wheel rebuild or native message compiler is needed for development. Native +rosbags classes/codecs are initialized in memory from installed schemas; this is +not precompiled Python class delivery. Constructors require explicit fields, even +when `.msg` declares a default. Restart Python +processes after changing generated classes. Editing `.msg` alone does not change +installed classes: the drift check rejects missing, stale or changed outputs +until you explicitly regenerate and commit them. Import and check the new value: + + +```python skip +from dimos_generated.dimos_msgs.msg import DeviceReading +from dimos_generated.std_msgs.msg import Header +from dimos_generated.builtin_interfaces.msg import Time +from dimos_cdrgen.registry import encode, decode + +reading = DeviceReading( + header=Header(stamp=Time(sec=0, nanosec=0), frame_id="sensor"), + sequence=1, value=20.5, label="sensor", +) +assert type(reading.header) is Header +assert decode(encode(reading), DeviceReading).value == 20.5 +``` + +Run the package and runtime regressions appropriate to your changed consumers: + +```sh skip +.venv/bin/python -m pytest dimos/message_codegen/test_definitions.py \ + dimos/message_codegen/test_stubs.py +``` + +In the runtime-cutover layer, use the same +`Module`/`In[DeviceReading]`/`Out[DeviceReading]` API as other generated messages. +Do not use `dimos build` at the repository root for this workflow: that command +builds an **external message project**, not all built-in messages. + +The main CI **Built-in message alignment** check fails `ci-complete` if definitions, +package versions, generator/templates, or any checked-in output drift. Python, +C++ source projects, Rust build-script/schema inputs and viewer schemas are committed; the check independently regenerates +in a temporary directory and includes new/untracked and deleted files. Prepare +Rust 1.92.0 with `rustup toolchain install 1.92.0 --component rustfmt` once. +[The alignment guide](/docs/development/message-alignment.md) gives the small +locked check environment and repair commands; CI does not make bot commits. + +## Package artifacts and CI distribution + +CI builds the committed generated source as an ordinary compiler-free Python +wheel/sdist; wheel users do not need an editable checkout: + +```sh skip +uv build packages/dimos-generated --python .venv/bin/python \ + --out-dir build/message-codegen/ux-wheelhouse +``` + +## Native artifacts + +Build native source inputs/schemas and the Rust crate with the package's configured +version: + +```sh skip +bash scripts/package_messages.sh +``` + +Artifacts land in `build/message-codegen/release/dist/`: a +`dimos-messages-sources-0.1.0.tar.gz` and `dimos-generated-messages-0.1.0.crate` for +the current proposal version. The C++ archive contains source inputs, not a +header-only or prebuilt SDK. The shared `prepare_cpp` build core must generate and +compile the upstream ROSIDL typesupport and support libraries before consumption. +C++ distribution is source-only; prebuilt native SDK archives are out of scope. +CMake consumers use `dimos_generated::messages`; +Rust consumers use the `dimos-generated-messages` dependency. Native module +applications additionally need the transport SDK and its native dependencies; +a message wheel alone does not supply an installed SDK. + +CI builds the Python wheel/sdist and native artifacts and verifies consumers. +Python users install matching wheels without this maintainer generation workflow. Changes to wire layout require matching rebuilt +producers and typed consumers. Version changes must update dependency pins +consistently; package registry publication is a separate release operation. + +See [message contracts](/docs/development/message-reference.md) for shared type +ownership, schema distribution and value/helper boundaries. diff --git a/docs/development/messages.md b/docs/development/messages.md new file mode 100644 index 00000000000..48c7484f20c --- /dev/null +++ b/docs/development/messages.md @@ -0,0 +1,12 @@ +# Define and use messages + +Choose the workflow that owns your definitions: + +- [Develop a built-in message in this checkout](/docs/development/messages-in-repository.md): edit canonical `.msg` inputs, rebuild the independent message package, test consumers, and let CI distribute artifacts. +- [Use installed dimOS with a custom message project](/docs/development/messages-external-project.md): prepare matching review packages, define one external message and build/install it for Python, C++ and Rust. + +Both workflows share [message contracts](/docs/development/message-reference.md): +type ownership, language builds, schema distribution and generated values versus +runtime helpers. These APIs currently belong to the CDR proposal, not a public +release. `dimos build` targets external projects; it is not the built-in rebuild +command. diff --git a/examples/message-codegen/user-story/consumer.cpp b/examples/message-codegen/user-story/consumer.cpp new file mode 100644 index 00000000000..b8c74be2c91 --- /dev/null +++ b/examples/message-codegen/user-story/consumer.cpp @@ -0,0 +1,30 @@ +// Copyright 2026 Dimensional Inc. +// SPDX-License-Identifier: Apache-2.0 + +#include +#include +#include +#include +#include +#include + +int main(int argc, char** argv) { + if (argc != 3) return 2; + try { + std::ifstream input(argv[1], std::ios::binary); + if (!input) throw std::runtime_error("Cannot open input"); + std::vector bytes((std::istreambuf_iterator(input)), {}); + auto message = dimos::native::cdr_decode(bytes); + ++message.sequence; + message.value += 1; + message.label += "/cpp"; + std::cout << "C++ consumer: value=" << message.value << " label=" << message.label << '\n'; + auto encoded = dimos::native::cdr_encode(message); + std::ofstream output(argv[2], std::ios::binary); + output.write(reinterpret_cast(encoded.data()), encoded.size()); + if (!output) throw std::runtime_error("Cannot write output"); + } catch (const std::exception& error) { + std::cerr << error.what() << '\n'; + return 1; + } +} diff --git a/examples/message-codegen/user-story/consumer.rs b/examples/message-codegen/user-story/consumer.rs new file mode 100644 index 00000000000..5c201659bf3 --- /dev/null +++ b/examples/message-codegen/user-story/consumer.rs @@ -0,0 +1,42 @@ +// Copyright 2026 Dimensional Inc. +// +// 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. + +use story_messages_messages::story_msgs::msg::device_reading::DeviceReading; + +fn main() -> Result<(), Box> { + let args: Vec = std::env::args().collect(); + if args.len() != 3 { + return Err("usage: story-consumer INPUT OUTPUT".into()); + } + let wire = std::fs::read(&args[1])?; + if wire.get(..4) != Some(&[0, 1, 0, 0]) { + return Err("expected little-endian CDR".into()); + } + let (mut message, consumed) = + re_cdr::from_bytes::(&wire[4..])?; + if consumed != wire.len() - 4 { + return Err("trailing CDR bytes".into()); + } + message.sequence += 1; + message.value += 1.0; + message.label.push_str("/rust"); + println!( + "Rust consumer: value={} label={}", + message.value, message.label + ); + let mut output = vec![0, 1, 0, 0]; + output.extend(re_cdr::to_vec::<_, re_cdr::LittleEndian>(&message)?); + std::fs::write(&args[2], output)?; + Ok(()) +} diff --git a/examples/message-codegen/user-story/demo_module.py b/examples/message-codegen/user-story/demo_module.py new file mode 100644 index 00000000000..b4eb4bf68cd --- /dev/null +++ b/examples/message-codegen/user-story/demo_module.py @@ -0,0 +1,104 @@ +# Copyright 2026 Dimensional Inc. +# +# 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. + +"""Use an application-local generated message in a Python module and file relay.""" + +import argparse +from pathlib import Path +import subprocess + +from dimos_cdrgen.registry import decode, encode +from dimos_generated.builtin_interfaces.msg import Time +from dimos_generated.std_msgs.msg import Header +from story_messages.story_msgs.msg import DeviceReading + +from dimos.core.global_config import global_config +from dimos.core.module import Module +from dimos.core.stream import In, Out + + +class ReadingProcessor(Module): + reading: In[DeviceReading] + processed: Out[DeviceReading] + + def handle_reading(self, message: DeviceReading) -> None: + result = decode(encode(message), DeviceReading) + result.value += 1 + result.label += "/python" + self.processed.publish(result) + + +def main() -> None: + parser = argparse.ArgumentParser(description=__doc__) + parser.add_argument("--build", type=Path, required=True) + args = parser.parse_args() + # This file-relay acceptance needs local RPC only, never LAN discovery. + global_config.update( + transport="zenoh", + robot_ip="", + robot_ips="", + zenoh_connect="", + zenoh_scouting=False, + zenoh_multicast=False, + zenoh_gossip=False, + ) + processor = ReadingProcessor() + outputs: list[DeviceReading] = [] + unsubscribe = processor.processed.subscribe(outputs.append) + try: + reading = DeviceReading( + header=Header(stamp=Time(sec=1700000000, nanosec=123456789), frame_id="sensor"), + sequence=40, + value=20.5, + label="new-local-type", + ) + processor.handle_reading(decode(encode(reading), DeviceReading)) + assert len(outputs) == 1 + output = outputs[0] + print(f"Python module: {output.__msgtype__}, value={output.value}, label={output.label}") + evidence = args.build / "evidence" + evidence.mkdir(parents=True, exist_ok=True) + (evidence / "python.cdr").write_bytes(encode(output)) + subprocess.run( + [ + str(args.build / "cpp-consumer"), + str(evidence / "python.cdr"), + str(evidence / "cpp.cdr"), + ], + check=True, + ) + subprocess.run( + [ + str(args.build / "rust/target/debug/story-consumer"), + str(evidence / "cpp.cdr"), + str(evidence / "rust.cdr"), + ], + check=True, + ) + final = decode((evidence / "rust.cdr").read_bytes(), DeviceReading) + assert final.sequence == 42 + assert final.value == 23.5 + assert final.label == "new-local-type/python/cpp/rust" + assert final.header.stamp.nanosec == 123456789 + print( + f"Python receives: sequence={final.sequence}, value={final.value}, label={final.label}" + ) + print("PASS: application-local message crosses Python module, C++, Rust and Python") + finally: + unsubscribe() + processor.stop() + + +if __name__ == "__main__": + main() diff --git a/examples/message-project/.gitignore b/examples/message-project/.gitignore new file mode 100644 index 00000000000..36b54060ba9 --- /dev/null +++ b/examples/message-project/.gitignore @@ -0,0 +1,5 @@ +/build/ +/dist/ +/sdk/ +/.venv/ +/rust/target/ diff --git a/examples/message-project/cpp/CMakeLists.txt b/examples/message-project/cpp/CMakeLists.txt new file mode 100644 index 00000000000..62b118da718 --- /dev/null +++ b/examples/message-project/cpp/CMakeLists.txt @@ -0,0 +1,6 @@ +cmake_minimum_required(VERSION 3.20) +project(reading_processor LANGUAGES CXX) +find_package(dimos_native CONFIG REQUIRED) +find_package(story_messages CONFIG REQUIRED) +add_executable(processor processor.cpp) +target_link_libraries(processor PRIVATE dimos_native::dimos_native story_messages::messages) diff --git a/examples/message-project/cpp/CMakePresets.json b/examples/message-project/cpp/CMakePresets.json new file mode 100644 index 00000000000..a256fdff4e2 --- /dev/null +++ b/examples/message-project/cpp/CMakePresets.json @@ -0,0 +1,18 @@ +{ + "version": 3, + "configurePresets": [ + { + "name": "dimos", + "generator": "Unix Makefiles", + "binaryDir": "${sourceDir}/../build/cpp", + "toolchainFile": "${sourceDir}/../build/dimos/toolchain.cmake" + } + ], + "buildPresets": [ + { + "name": "dimos", + "configurePreset": "dimos", + "jobs": 2 + } + ] +} diff --git a/examples/message-project/cpp/processor.cpp b/examples/message-project/cpp/processor.cpp new file mode 100644 index 00000000000..9e19e873645 --- /dev/null +++ b/examples/message-project/cpp/processor.cpp @@ -0,0 +1,23 @@ +// Copyright 2026 Dimensional Inc. +// SPDX-License-Identifier: Apache-2.0 +#include +#include + +using namespace dimos::native; +using Reading = story_msgs::msg::DeviceReading; + +class Processor : public Module { + Output processed_; +public: + void build(Builder& builder, Config&) override { + processed_ = builder.output("processed"); + builder.input("reading", &Processor::process, this); + } + void process(const Reading& input) { + auto output = input; + output.value += 1; + processed_.publish(output); + } +}; + +int main() { run_with_transport(); } diff --git a/examples/message-project/demo_blueprint.py b/examples/message-project/demo_blueprint.py new file mode 100644 index 00000000000..117d650a438 --- /dev/null +++ b/examples/message-project/demo_blueprint.py @@ -0,0 +1,132 @@ +# Copyright 2026 Dimensional Inc. +# +# 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. + +"""Run the documented custom message through actual Python/C++/Rust workers.""" + +import argparse +from contextlib import ExitStack +from functools import partial +from pathlib import Path +import socket +import threading +from unittest.mock import patch +import uuid + +from demo_modules import ReadingProcessor +from dimos_cdrgen.registry import encode as cdr_encode +from dimos_generated.builtin_interfaces.msg import Time +from dimos_generated.std_msgs.msg import Header +from story_messages.story_msgs.msg import DeviceReading + +from dimos.core.coordination.blueprints import Blueprint, autoconnect +from dimos.core.coordination.module_coordinator import ModuleCoordinator +from dimos.core.core import rpc +from dimos.core.module import Module +from dimos.core.native_module import NativeModule +from dimos.core.stream import In, Out +from dimos.protocol.service.system_configurator.base import configure_system +from dimos.protocol.service.zenohservice import ZenohConfig, ZenohSessionPool + + +class Exchange(Module): + raw: Out[DeviceReading] + checked: In[DeviceReading] + + @rpc + def start(self) -> None: + self.received: DeviceReading | None = None + self.done = threading.Event() + super().start() + + async def handle_checked(self, message: DeviceReading) -> None: + self.received = message + self.done.set() + + @rpc + def exchange(self) -> str: + message = DeviceReading( + header=Header(stamp=Time(sec=17, nanosec=123456789), frame_id="sensor"), + sequence=42, + value=20.5, + label="sensor", + ) + for _ in range(60): + self.raw.publish(message) + if self.done.wait(0.25): + break + if self.received is None: + raise TimeoutError("No reply from the three-language module chain") + expected = DeviceReading(header=message.header, sequence=42, value=23.5, label="sensor") + if cdr_encode(self.received) != cdr_encode(expected): + raise ValueError("Received fields differ from the expected three module edits") + return "PASS: 20.5 -> Python 21.5 -> C++ 22.5 -> Rust 23.5; Header and sequence preserved" + + +class CppProcessor(NativeModule): + reading: In[DeviceReading] + processed: Out[DeviceReading] + + +class RustProcessor(NativeModule): + processed: In[DeviceReading] + checked: Out[DeviceReading] + + +def blueprint(cpp: Path, rust: Path) -> Blueprint: + return autoconnect( + Exchange.blueprint(), + ReadingProcessor.blueprint(), + CppProcessor.blueprint(executable=str(cpp.resolve()), stdin_config=True), + RustProcessor.blueprint(executable=str(rust.resolve()), stdin_config=True), + ).namespace("reading" + uuid.uuid4().hex[:8]) + + +def main() -> None: + parser = argparse.ArgumentParser(description=__doc__) + parser.add_argument("--transport", choices=["zenoh", "lcm"], default="zenoh") + args = parser.parse_args() + root = Path(__file__).resolve().parent + cpp, rust = root / "build/cpp/processor", root / "rust/target/debug/reading-processor" + if not cpp.is_file() or not rust.is_file(): + parser.error("Build both native processors before running this example") + with ExitStack() as stack: + # This finite offline example can report tuning needs but must never apply them. + stack.enter_context( + patch( + "dimos.protocol.service.system_configurator.base.configure_system", + partial(configure_system, check_only=True), + ) + ) + configured = blueprint(cpp, rust).global_config(viewer="none", transport=args.transport) + if args.transport == "zenoh": + with socket.socket() as reservation: + reservation.bind(("127.0.0.1", 0)) + endpoint = f"tcp/127.0.0.1:{reservation.getsockname()[1]}" + pool = ZenohSessionPool() + stack.callback(pool.close_all) + pool.acquire( + ZenohConfig( + mode="router", listen=[endpoint], connect=[], multicast=False, gossip=False + ) + ) + configured = configured.global_config( + zenoh_mode="client", zenoh_connect=endpoint, zenoh_multicast=False + ) + coordinator = ModuleCoordinator.build(configured) + stack.callback(coordinator.stop) + print(coordinator.get_instance(Exchange).exchange(), flush=True) + + +if __name__ == "__main__": + main() diff --git a/examples/message-project/demo_modules.py b/examples/message-project/demo_modules.py new file mode 100644 index 00000000000..c2cc571223c --- /dev/null +++ b/examples/message-project/demo_modules.py @@ -0,0 +1,35 @@ +# Copyright 2026 Dimensional Inc. +# +# 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. + +"""The exact message and module snippets used in the message-authoring walkthrough.""" + +from story_messages.story_msgs.msg import DeviceReading + +from dimos.core.module import Module +from dimos.core.stream import In, Out + + +class ReadingProcessor(Module): + raw: In[DeviceReading] + reading: Out[DeviceReading] + + async def handle_raw(self, message: DeviceReading) -> None: + self.reading.publish( + DeviceReading( + header=message.header, + sequence=message.sequence, + value=message.value + 1, + label=message.label, + ) + ) diff --git a/examples/message-project/interfaces/story_msgs/msg/DeviceReading.msg b/examples/message-project/interfaces/story_msgs/msg/DeviceReading.msg new file mode 100644 index 00000000000..1bfea6b684f --- /dev/null +++ b/examples/message-project/interfaces/story_msgs/msg/DeviceReading.msg @@ -0,0 +1,4 @@ +std_msgs/Header header +uint32 sequence +float64 value +string label "sensor" diff --git a/examples/message-project/pyproject.toml b/examples/message-project/pyproject.toml new file mode 100644 index 00000000000..e6aefaf0d6b --- /dev/null +++ b/examples/message-project/pyproject.toml @@ -0,0 +1,10 @@ +[build-system] +requires = ["dimos-message-project==0.1.0"] +build-backend = "dimos_message_project.backend" + +[project] +name = "story-messages" +version = "0.1.0" + +[tool.dimos.messages] +languages = ["python", "cpp", "rust"] diff --git a/examples/message-project/rust/Cargo.lock b/examples/message-project/rust/Cargo.lock new file mode 100644 index 00000000000..8ce3ef42073 --- /dev/null +++ b/examples/message-project/rust/Cargo.lock @@ -0,0 +1,4407 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "adler2" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa" + +[[package]] +name = "advisory-lock" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a6caee7d48f930f9ad3fc9546f8cbf843365da0c5b0ca4eee1d1ac3dd12d8f93" +dependencies = [ + "libc", + "winapi", +] + +[[package]] +name = "aes" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b169f7a6d4742236a0a00c541b845991d0ac43e546831af1249753ab4c3aa3a0" +dependencies = [ + "cfg-if", + "cipher", + "cpufeatures 0.2.17", +] + +[[package]] +name = "ahash" +version = "0.8.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a15f179cd60c4584b8a8c596927aadc462e27f2ca70c04e0071964a73ba7a75" +dependencies = [ + "cfg-if", + "getrandom 0.3.4", + "once_cell", + "version_check", + "zerocopy", +] + +[[package]] +name = "aho-corasick" +version = "1.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c982642fa9e8606056828ee9a8505737230110bb1099153c79efe865c59d12ba" +dependencies = [ + "memchr", +] + +[[package]] +name = "allocator-api2" +version = "0.2.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923" + +[[package]] +name = "android_system_properties" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae221649c9976a6f6c56ae1facf410f3ddb33cc661c4b7b61020a912d4237fbc" +dependencies = [ + "libc", +] + +[[package]] +name = "anyhow" +version = "1.0.104" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "330a5ed07fa54e4702c9d6c4174f74427fc0ef6e214bbd677ae50a5099946470" + +[[package]] +name = "approx" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cab112f0a86d568ea0e627cc1d6be74a1e9cd55214684db5561995f6dad897c6" +dependencies = [ + "num-traits", +] + +[[package]] +name = "arc-swap" +version = "1.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c049c0be4daef0b145cb3555416b3b8ef5b7888a38aea1a3a155801fe7b0810b" +dependencies = [ + "rustversion", +] + +[[package]] +name = "array-init" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d62b7694a562cdf5a74227903507c56ab2cc8bdd1f781ed5cb4cf9c9f810bfc" + +[[package]] +name = "asn1-rs" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7f43a50ac4fdca5df8e885c21b835997f0a1cdee65494a6847694a98652d9d8" +dependencies = [ + "asn1-rs-derive", + "asn1-rs-impl", + "displaydoc", + "nom", + "num-traits", + "rusticata-macros", + "thiserror", + "time", +] + +[[package]] +name = "asn1-rs-derive" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3109e49b1e4909e9db6515a30c633684d68cdeaa252f215214cb4fa1a5bfee2c" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", + "synstructure", +] + +[[package]] +name = "asn1-rs-impl" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b18050c2cd6fe86c3a76584ef5e0baf286d038cda203eb6223df2cc413565f7" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "async-trait" +version = "0.1.92" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "82f6aeea286b8eb4dd3431a1be1b59d290ace00f5bfd8e2a159bc2a05e2c1667" +dependencies = [ + "proc-macro2", + "quote", + "syn 3.0.6", +] + +[[package]] +name = "autocfg" +version = "1.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2032f911046de80f0a198e0901378627c33f59ea0ac00e363d481118bd70a53" + +[[package]] +name = "base64" +version = "0.22.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" + +[[package]] +name = "base64" +version = "0.23.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac07cdecf99051d9a5238b80f35af32cdeba5b336e55d957b318b50137e18da5" + +[[package]] +name = "bit-vec" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b71798fca2c1fe1086445a7258a4bc81e6e49dcd24c8d0dd9a1e57395b603f51" +dependencies = [ + "serde", +] + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "bitflags" +version = "2.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b588b76d00fde79687d7646a9b5bdf3cc0f655e0bbd080335a95d7e96f3587da" +dependencies = [ + "serde_core", +] + +[[package]] +name = "block-buffer" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" +dependencies = [ + "generic-array", +] + +[[package]] +name = "bs58" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf88ba1141d185c399bee5288d850d63b8369520c1eafc32a0430b5b6c287bf4" +dependencies = [ + "tinyvec", +] + +[[package]] +name = "buddy_system_allocator" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7913f22349ffcfc6ca0ca9a656ec26cfbba538ed49c31a273dff2c5d1ea83d9" +dependencies = [ + "spin 0.9.9", +] + +[[package]] +name = "bumpalo" +version = "3.20.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72f5acc6cb2ba439de613abc23857ec3d78374d8ed5ac84e9d11336e87da8649" + +[[package]] +name = "bytemuck" +version = "1.25.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95832e849adfb21180ccb6826a99da14e5d266ae5c2e668e1602cf234f153797" +dependencies = [ + "bytemuck_derive", +] + +[[package]] +name = "bytemuck_derive" +version = "1.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a1f896587b6f2c069c73d2f0913e2d590c3990285cd2f0b6aa02b786b4c679c" +dependencies = [ + "proc-macro2", + "quote", + "syn 3.0.6", +] + +[[package]] +name = "byteorder" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" + +[[package]] +name = "bytes" +version = "1.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc652a48c352aef3ea3aed32080501cf3ef6ed5da78602a020c991775b0aff04" + +[[package]] +name = "cc" +version = "1.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ad534f4357a5264cce5019c989cf66a4f0dc4e0d1b1d15f8aacec0ff7360273" +dependencies = [ + "find-msvc-tools", + "shlex", +] + +[[package]] +name = "cfg-if" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" + +[[package]] +name = "cfg_aliases" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd16c4719339c4530435d38e511904438d07cce7950afa3718a84ac36c10e89e" + +[[package]] +name = "cfg_aliases" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f079e83a288787bcd14a6aea84cee5c87a67c5a3e660c30f557a3d24761b3527" + +[[package]] +name = "chacha20" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "65c35e4b699c7e15ccbe7ee35c005e4fc0a278d22238a2857e6ce2dadeda1b06" +dependencies = [ + "cfg-if", + "cpufeatures 0.3.1", + "rand_core 0.10.1", +] + +[[package]] +name = "chrono" +version = "0.4.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1aa79e62e7697b8e29b513a68abacf485adcd1fe8284a4316c5ae868e6633327" +dependencies = [ + "iana-time-zone", + "num-traits", + "serde", + "windows-link", +] + +[[package]] +name = "cipher" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad" +dependencies = [ + "crypto-common", + "inout", +] + +[[package]] +name = "combine" +version = "4.6.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfc320937d09e6de266b31b9afb480f197d7a861be86be7cb2ea7e5d1bfffc5e" +dependencies = [ + "bytes", + "memchr", +] + +[[package]] +name = "const_format" +version = "0.2.36" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4481a617ad9a412be3b97c5d403fef8ed023103368908b9c50af598ff467cc1e" +dependencies = [ + "const_format_proc_macros", + "konst", +] + +[[package]] +name = "const_format_proc_macros" +version = "0.2.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d57c2eccfb16dbac1f4e61e206105db5820c9d26c3c472bc17c774259ef7744" +dependencies = [ + "proc-macro2", + "quote", + "unicode-xid", +] + +[[package]] +name = "core-foundation" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2a6cd9ae233e7f62ba4e9353e81a88df7fc8a5987b8d445b4d90c879bd156f6" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "core-foundation-sys" +version = "0.8.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" + +[[package]] +name = "cpufeatures" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280" +dependencies = [ + "libc", +] + +[[package]] +name = "cpufeatures" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ca28b0ae3115b884660db4118d803791fd6756b6e88f39c0f3f7859060d7566" +dependencies = [ + "libc", +] + +[[package]] +name = "crc32fast" +version = "1.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8498c871161e1742aaa9d52551b2d6ebdd4c3d45a3be423e3728f33b955be550" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "crossbeam" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1137cd7e7fc0fb5d3c5a8678be38ec56e819125d8d7907411fe24ccb943faca8" +dependencies = [ + "crossbeam-channel", + "crossbeam-deque", + "crossbeam-epoch", + "crossbeam-queue", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-channel" +version = "0.5.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d85363c37faeca707aef026efa9f3b34d077bce547e48f770770625c6013679e" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-deque" +version = "0.8.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5181e0de7b61eb03a81e347d6dd8797bae9da5146707b51077e2d71a54ec0ceb" +dependencies = [ + "crossbeam-epoch", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-epoch" +version = "0.9.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d6914041f254d6e9176c01941b21115dcfb7089e55135a35411081bd106ef3f" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-queue" +version = "0.3.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "803d13fb3b09d88be9f4dbc29062c66b19bf7170867ceb746d2a8689bf6c7a26" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61803da095bee82a81bb1a452ecc25d3b2f1416d1897eb86430c6159ef717c17" + +[[package]] +name = "crypto-common" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78c8292055d1c1df0cce5d180393dc8cce0abec0a7102adb6c7b1eef6016d60a" +dependencies = [ + "generic-array", + "typenum", +] + +[[package]] +name = "darling" +version = "0.23.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25ae13da2f202d56bd7f91c25fba009e7717a1e4a1cc98a76d844b65ae912e9d" +dependencies = [ + "darling_core", + "darling_macro", +] + +[[package]] +name = "darling_core" +version = "0.23.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9865a50f7c335f53564bb694ef660825eb8610e0a53d3e11bf1b0d3df31e03b0" +dependencies = [ + "ident_case", + "proc-macro2", + "quote", + "strsim", + "syn 2.0.119", +] + +[[package]] +name = "darling_macro" +version = "0.23.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3984ec7bd6cfa798e62b4a642426a5be0e68f9401cfc2a01e3fa9ea2fcdb8d" +dependencies = [ + "darling_core", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "data-encoding" +version = "2.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4583a4551df46e2792f82ceeac45e850d2e2d5debba0b91f102385cda5b11f06" + +[[package]] +name = "defmt" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2953bfe4f93bbd20cc71198842756f77d161884c99ebbabc41d80231ded88d1" +dependencies = [ + "bitflags 1.3.2", + "defmt-macros", +] + +[[package]] +name = "defmt-macros" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bad9c72e7ca2137e0dc3813245a0d282fd6daad32fd800af018306a9169b5fe8" +dependencies = [ + "defmt-parser", + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "defmt-parser" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "10d60334b3b2e7c9d91ef8150abfb6fa4c1c39ebbcf4a81c2e346aad939fee3e" +dependencies = [ + "thiserror", +] + +[[package]] +name = "der-parser" +version = "10.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07da5016415d5a3c4dd39b11ed26f915f52fc4e0dc197d87908bc916e51bc1a6" +dependencies = [ + "asn1-rs", + "displaydoc", + "nom", + "num-bigint", + "num-traits", + "rusticata-macros", +] + +[[package]] +name = "deranged" +version = "0.5.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7cd812cc2bc1d69d4764bd80df88b4317eaef9e773c75226407d9bc0876b211c" +dependencies = [ + "serde_core", +] + +[[package]] +name = "digest" +version = "0.10.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" +dependencies = [ + "block-buffer", + "crypto-common", + "subtle", +] + +[[package]] +name = "dimos-generated-messages" +version = "0.1.0" +dependencies = [ + "heapless", + "re_cdr", + "ros2msg", + "serde", + "serde-big-array", +] + +[[package]] +name = "dimos-lcm-transport" +version = "0.1.0" +dependencies = [ + "byteorder", + "socket2 0.5.10", + "tokio", +] + +[[package]] +name = "dimos-module" +version = "0.1.0" +dependencies = [ + "dimos-generated-messages", + "dimos-lcm-transport", + "dimos-module-macros", + "nalgebra", + "rayon", + "re_cdr", + "serde", + "serde_json", + "tokio", + "tracing", + "tracing-subscriber", + "url", + "validator", + "zenoh", +] + +[[package]] +name = "dimos-module-macros" +version = "0.1.0" +dependencies = [ + "proc-macro2", + "quote", + "syn 3.0.6", + "toml 1.1.4+spec-1.1.0", +] + +[[package]] +name = "dirs" +version = "6.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3e8aa94d75141228480295a7d0e7feb620b1a5ad9f12bc40be62411e38cce4e" +dependencies = [ + "dirs-sys", +] + +[[package]] +name = "dirs-sys" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e01a3366d27ee9890022452ee61b2b63a67e6f13f58900b651ff5665f0bb1fab" +dependencies = [ + "libc", + "option-ext", + "redox_users", + "windows-sys 0.61.2", +] + +[[package]] +name = "displaydoc" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c6232dd377dcc64799954cbd3a9bb882e9cdc1308ccd87b1c098f1fb2eaf82a8" +dependencies = [ + "proc-macro2", + "quote", + "syn 3.0.6", +] + +[[package]] +name = "dtoa" +version = "1.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c3cf4824e2d5f025c7b531afcb2325364084a16806f6d47fbc1f5fbd9960590" + +[[package]] +name = "dyn-clone" +version = "1.0.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d0881ea181b1df73ff77ffaaf9c7544ecc11e82fba9b5f27b262a3c73a332555" + +[[package]] +name = "either" +version = "1.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "252afb9ae5eaa683babdc6a068b3f5726eb19e05070c731f9b2a23a7c3e8ed34" + +[[package]] +name = "equivalent" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" + +[[package]] +name = "errno" +version = "0.3.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" +dependencies = [ + "libc", + "windows-sys 0.61.2", +] + +[[package]] +name = "event-listener" +version = "5.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a23add41df1562121a9393cb065eab5146a1242410f23a644851e90cfd669d2" +dependencies = [ + "parking", + "pin-project-lite", +] + +[[package]] +name = "fastbloom" +version = "0.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef975e30683b2d965054bb0a836f8973857c4ebf6acf274fe46617cd285060d8" +dependencies = [ + "foldhash 0.2.0", + "libm", + "portable-atomic", + "siphasher", +] + +[[package]] +name = "fastrand" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da7c62ceae207dd37ea5b845da6a0696c799f85e97da1ab5b7910be3c1c80223" + +[[package]] +name = "find-msvc-tools" +version = "0.1.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d45db016d36b838f563236e9193d0ee6ce38f3f68b6c94e914b4929c96bbb890" + +[[package]] +name = "fixedbitset" +version = "0.5.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d674e81391d1e1ab681a28d99df07927c6d4aa5b027d7da16ba32d1d21ecd99" + +[[package]] +name = "flate2" +version = "1.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e634e2e0ebac1ee034020da1ca582e17ffe4e0f5e985823721e168928136dcb" +dependencies = [ + "crc32fast", + "miniz_oxide", + "zlib-rs", +] + +[[package]] +name = "flume" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da0e4dd2a88388a1f4ccc7c9ce104604dab68d9f408dc34cd45823d5a9069095" +dependencies = [ + "futures-core", + "futures-sink", + "nanorand", + "spin 0.9.9", +] + +[[package]] +name = "foldhash" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2" + +[[package]] +name = "foldhash" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77ce24cb58228fbb8aa041425bb1050850ac19177686ea6e0f41a70416f56fdb" + +[[package]] +name = "form_urlencoded" +version = "1.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb4cb245038516f5f85277875cdaa4f7d2c9a0fa0468de06ed190163b1581fcf" +dependencies = [ + "percent-encoding", +] + +[[package]] +name = "futures" +version = "0.3.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a31d2a3fbaaeb2af2368bbdd904aa8e812d3c04a1ee10d3171f52d556e5d0a3" +dependencies = [ + "futures-channel", + "futures-core", + "futures-executor", + "futures-io", + "futures-sink", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-channel" +version = "0.3.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1f9e3d69d39e4862ffed03ed071a76f9a13ba1d9109d355b0f0aa6b15e393c4" +dependencies = [ + "futures-core", + "futures-sink", +] + +[[package]] +name = "futures-core" +version = "0.3.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92d699e522242e69e3003b94ecc1f960f3a5e015aa7c5d7486e65ad01dd94f5e" + +[[package]] +name = "futures-executor" +version = "0.3.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "031b47cf1a3c6cc8bc2fc76cd437f521619387907d469316e7c0bc278f1f5432" +dependencies = [ + "futures-core", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-io" +version = "0.3.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53c0fa8157de1303bfffdaa1cc2a673bfffb60102f76b0ef4441659124373fed" + +[[package]] +name = "futures-macro" +version = "0.3.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9fb9654ba8355388abeb8dcb4fc62f511300867002afc858860463bdd9fe0c44" +dependencies = [ + "proc-macro2", + "quote", + "syn 3.0.6", +] + +[[package]] +name = "futures-sink" +version = "0.3.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1944426bf7d03f1d14f708785e4b33efd750b36d48a157b836b3efc15ede8e1d" + +[[package]] +name = "futures-task" +version = "0.3.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd417de3d1d015fc3bfd2b1ea46dfc7bab72ef86f1cc7cc9c78e728b34a6d1fd" + +[[package]] +name = "futures-util" +version = "0.3.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d50a92467f8ba5dd6e3ee5d4bd04d73ab2e4e1c44474a0674821dfce14b79bc" +dependencies = [ + "futures-channel", + "futures-core", + "futures-io", + "futures-macro", + "futures-sink", + "futures-task", + "memchr", + "pin-project-lite", + "slab", +] + +[[package]] +name = "generic-array" +version = "0.14.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" +dependencies = [ + "typenum", + "version_check", +] + +[[package]] +name = "getrandom" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff2abc00be7fca6ebc474524697ae276ad847ad0a6b3faa4bcb027e9a4614ad0" +dependencies = [ + "cfg-if", + "js-sys", + "libc", + "wasi", + "wasm-bindgen", +] + +[[package]] +name = "getrandom" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd" +dependencies = [ + "cfg-if", + "libc", + "r-efi 5.3.0", + "wasip2", +] + +[[package]] +name = "getrandom" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "300e883d756b2e4ec94e02791f39b04b522276138852cfc41d9fb7e904106099" +dependencies = [ + "cfg-if", + "js-sys", + "libc", + "r-efi 6.0.0", + "rand_core 0.10.1", + "wasm-bindgen", +] + +[[package]] +name = "git-version" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ad568aa3db0fcbc81f2f116137f263d7304f512a1209b35b85150d3ef88ad19" +dependencies = [ + "git-version-macro", +] + +[[package]] +name = "git-version-macro" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53010ccb100b96a67bc32c0175f0ed1426b31b655d562898e57325f81c023ac0" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "glam" +version = "0.30.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19fc433e8437a212d1b6f1e68c7824af3aed907da60afa994e7f542d18d12aa9" + +[[package]] +name = "glam" +version = "0.31.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "556f6b2ea90b8d15a74e0e7bb41671c9bdf38cd9f78c284d750b9ce58a2b5be7" + +[[package]] +name = "glam" +version = "0.32.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f70749695b063ecbf6b62949ccccde2e733ec3ecbbd71d467dca4e5c6c97cca0" + +[[package]] +name = "glam" +version = "0.33.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "21fef0953c54fd3de2f44b743fbf77e044c81a25faee03636dfccc0d35135e23" + +[[package]] +name = "hash32" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47d60b12902ba28e2730cd37e95b8c9223af2808df9e902d4df49588d1470606" +dependencies = [ + "byteorder", +] + +[[package]] +name = "hashbrown" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" + +[[package]] +name = "hashbrown" +version = "0.14.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" +dependencies = [ + "ahash", + "allocator-api2", +] + +[[package]] +name = "hashbrown" +version = "0.15.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1" +dependencies = [ + "foldhash 0.1.5", +] + +[[package]] +name = "hashbrown" +version = "0.16.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100" +dependencies = [ + "allocator-api2", + "equivalent", + "foldhash 0.2.0", +] + +[[package]] +name = "hashbrown" +version = "0.17.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed5909b6e89a2db4456e54cd5f673791d7eca6732202bbf2a9cc504fe2f9b84a" + +[[package]] +name = "heapless" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0bfb9eb618601c89945a70e254898da93b13be0388091d42117462b265bb3fad" +dependencies = [ + "hash32", + "serde", + "stable_deref_trait", +] + +[[package]] +name = "heck" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" + +[[package]] +name = "hermit-abi" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e17592d60ebacc7d5e169f4663c5f84f9161cc90328abcfe8456f41e4dfcb284" + +[[package]] +name = "hex" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" + +[[package]] +name = "hmac" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" +dependencies = [ + "digest", +] + +[[package]] +name = "home" +version = "0.5.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc627f471c528ff0c4a49e1d5e60450c8f6461dd6d10ba9dcd3a61d3dff7728d" +dependencies = [ + "windows-sys 0.61.2", +] + +[[package]] +name = "humantime" +version = "2.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "15cdd26707701c53297e2fa6afb323d55fbc1d0810c3aec078ae3ef0424c3c15" + +[[package]] +name = "iana-time-zone" +version = "0.1.65" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e31bc9ad994ba00e440a8aa5c9ef0ec67d5cb5e5cb0cc7f8b744a35b389cc470" +dependencies = [ + "android_system_properties", + "core-foundation-sys", + "iana-time-zone-haiku", + "js-sys", + "log", + "wasm-bindgen", + "windows-core", +] + +[[package]] +name = "iana-time-zone-haiku" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" +dependencies = [ + "cc", +] + +[[package]] +name = "icu_collections" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa68d21081c4a05d5a901a1c62add574c77048b6a1c67be3b50ce0b60d4ca513" +dependencies = [ + "displaydoc", + "potential_utf", + "utf8_iter", + "yoke", + "zerofrom", + "zerovec", +] + +[[package]] +name = "icu_locale_core" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d56e28588da92eee5c3201a6eff33fabdd49b62269c8938d4ff050ce4d900deb" +dependencies = [ + "displaydoc", + "litemap", + "tinystr", + "writeable", + "zerovec", +] + +[[package]] +name = "icu_normalizer" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "12f9cf5f235641ed274641dd81c3f28d870e276763d0797aeeab72317b1c646f" +dependencies = [ + "icu_collections", + "icu_normalizer_data", + "icu_properties", + "icu_provider", + "smallvec", + "zerovec", +] + +[[package]] +name = "icu_normalizer_data" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1563da1ed3e0b3bf3d74c9b85917ac9c56464d2f57242270c09c9e752f8021a0" + +[[package]] +name = "icu_properties" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e7ca276ad3145661a65914e6daf131ca5120cd3dcee8f8f3214b8875184a148" +dependencies = [ + "displaydoc", + "icu_collections", + "icu_locale_core", + "icu_properties_data", + "icu_provider", + "zerotrie", + "zerovec", +] + +[[package]] +name = "icu_properties_data" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e590f038c1464a96894fd6d10127e90a8be4509f56ff7ecef851b15cee0b7caa" + +[[package]] +name = "icu_provider" +version = "2.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d27bbb9d3abbefac45d55f647c9de1d44aafcd1186eb91879afef17c396c3e73" +dependencies = [ + "displaydoc", + "icu_locale_core", + "writeable", + "yoke", + "zerofrom", + "zerotrie", + "zerovec", +] + +[[package]] +name = "ident_case" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" + +[[package]] +name = "idna" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b0875f23caa03898994f6ddc501886a45c7d3d62d04d2d90788d47be1b1e4de" +dependencies = [ + "idna_adapter", + "smallvec", + "utf8_iter", +] + +[[package]] +name = "idna_adapter" +version = "1.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb68373c0d6620ef8105e855e7745e18b0d00d3bdb07fb532e434244cdb9a714" +dependencies = [ + "icu_normalizer", + "icu_properties", +] + +[[package]] +name = "indexmap" +version = "1.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" +dependencies = [ + "autocfg", + "hashbrown 0.12.3", + "serde", +] + +[[package]] +name = "indexmap" +version = "2.14.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07aa2048142242915a31d35844fb311e0e53fcca590c3a0a40dcf1b841fa09eb" +dependencies = [ + "equivalent", + "hashbrown 0.17.1", + "serde", + "serde_core", +] + +[[package]] +name = "inout" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "879f10e63c20629ecabbb64a8010319738c66a5cd0c29b02d63d272b03751d01" +dependencies = [ + "generic-array", +] + +[[package]] +name = "ipnetwork" +version = "0.20.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf466541e9d546596ee94f9f69590f89473455f88372423e0008fc1a7daf100e" +dependencies = [ + "serde", +] + +[[package]] +name = "itertools" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b192c782037fadd9cfa75548310488aabdbf3d2da73885b31bd0abd03351285" +dependencies = [ + "either", +] + +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + +[[package]] +name = "jiff" +version = "0.2.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "668b7183bd07af9a4885f5c35b0cc5c83c4607a913c16b7e17291832910d2dcc" +dependencies = [ + "defmt", + "jiff-core", + "jiff-static", + "jiff-tzdb-platform", + "log", + "portable-atomic", + "portable-atomic-util", + "serde_core", + "windows-link", +] + +[[package]] +name = "jiff-core" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7feca88439efe53da3754500c1851dedf3cb36c524dd5cf8225cc0794de95d09" +dependencies = [ + "defmt", +] + +[[package]] +name = "jiff-static" +version = "0.2.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3a69dcb3a21cfb32ce1cd056169337ca284af0766dd766e7878819b251a49204" +dependencies = [ + "jiff-core", + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "jiff-tzdb" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "142bd39932ad231f10513df9ab62661fead8719872150b7ad02a2df79f4e141e" + +[[package]] +name = "jiff-tzdb-platform" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "875a5a69ac2bab1a891711cf5eccbec1ce0341ea805560dcd90b7a2e925132e8" +dependencies = [ + "jiff-tzdb", +] + +[[package]] +name = "jni" +version = "0.22.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5efd9a482cf3a427f00d6b35f14332adc7902ce91efb778580e180ff90fa3498" +dependencies = [ + "cfg-if", + "combine", + "jni-macros", + "jni-sys", + "log", + "simd_cesu8", + "thiserror", + "walkdir", + "windows-link", +] + +[[package]] +name = "jni-macros" +version = "0.22.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a00109accc170f0bdb141fed3e393c565b6f5e072365c3bd58f5b062591560a3" +dependencies = [ + "proc-macro2", + "quote", + "rustc_version", + "simd_cesu8", + "syn 2.0.119", +] + +[[package]] +name = "jni-sys" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c6377a88cb3910bee9b0fa88d4f42e1d2da8e79915598f65fb0c7ee14c878af2" +dependencies = [ + "jni-sys-macros", +] + +[[package]] +name = "jni-sys-macros" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38c0b942f458fe50cdac086d2f946512305e5631e720728f2a61aabcd47a6264" +dependencies = [ + "quote", + "syn 2.0.119", +] + +[[package]] +name = "js-sys" +version = "0.3.104" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0e0c1080212aad755ea003d18543e8768dd432c48819efd73a7bf1e39b7a5a3a" +dependencies = [ + "cfg-if", + "futures-util", + "wasm-bindgen", +] + +[[package]] +name = "json5" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96b0db21af676c1ce64250b5f40f3ce2cf27e4e47cb91ed91eb6fe9350b430c1" +dependencies = [ + "pest", + "pest_derive", + "serde", +] + +[[package]] +name = "keccak" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb26cec98cce3a3d96cbb7bced3c4b16e3d13f27ec56dbd62cbc8f39cfb9d653" +dependencies = [ + "cpufeatures 0.2.17", +] + +[[package]] +name = "keyed-set" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89d255a6b6ecd77bb93ce91de984d7039bff7503f500eb4851a1269732f22baf" +dependencies = [ + "hashbrown 0.14.5", +] + +[[package]] +name = "konst" +version = "0.2.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "128133ed7824fcd73d6e7b17957c5eb7bacb885649bd8c69708b2331a10bcefb" +dependencies = [ + "konst_macro_rules", +] + +[[package]] +name = "konst_macro_rules" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4933f3f57a8e9d9da04db23fb153356ecaf00cbd14aee46279c33dc80925c37" + +[[package]] +name = "lazy_static" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" + +[[package]] +name = "libc" +version = "0.2.189" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3eaf3ede3fee6db1a4c2ee091bf8a8b4dccdc6d17f656fb07896ee72867612f2" + +[[package]] +name = "libloading" +version = "0.8.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7c4b02199fee7c5d21a5ae7d8cfa79a6ef5bb2fc834d6e9058e89c825efdc55" +dependencies = [ + "cfg-if", + "windows-link", +] + +[[package]] +name = "libm" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6d2cec3eae94f9f509c767b45932f1ada8350c4bdb85af2fcab4a3c14807981" + +[[package]] +name = "libredox" +version = "0.1.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7955dfc218a8afb29dfeffd540e3a6e96baeb94fe7138228dd7cc6937fbbf96" +dependencies = [ + "libc", +] + +[[package]] +name = "litemap" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47d9d19d1d6efa0109d2f65ff4c85cddd50bd572e5a00127ab10987290bcefae" + +[[package]] +name = "lock_api" +version = "0.4.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "224399e74b87b5f3557511d98dff8b14089b3dadafcab6bb93eab67d3aace965" +dependencies = [ + "scopeguard", +] + +[[package]] +name = "lockfree" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "74ee94b5ad113c7cb98c5a040f783d0952ee4fe100993881d1673c2cb002dd23" +dependencies = [ + "owned-alloc", +] + +[[package]] +name = "log" +version = "0.4.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f9f8bd3e56ce4dfc153cf470fffbfa98c7620958b312ca5c3a4b8d5181fd13c6" + +[[package]] +name = "lru-slab" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "112b39cec0b298b6c1999fee3e31427f74f676e4cb9879ed1a121b43661a4154" + +[[package]] +name = "lz4_flex" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b8c72594ac26bfd34f2d99dfced2edfaddfe8a476e3ff2ca0eb293d925c4f83" +dependencies = [ + "twox-hash", +] + +[[package]] +name = "matchers" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d1525a2a28c7f4fa0fc98bb91ae755d1e2d1505079e05539e35bc876b5d65ae9" +dependencies = [ + "regex-automata", +] + +[[package]] +name = "matrixmultiply" +version = "0.3.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f607c237553f086e7043417a51df26b2eb899d3caff94e6a67592ff992fedc7" +dependencies = [ + "autocfg", + "rawpointer", +] + +[[package]] +name = "memchr" +version = "2.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf8baf1c55e62ffcace7a9f06f4bd9cd3f0c4beb022d3b367256b91b87513d98" + +[[package]] +name = "minimal-lexical" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" + +[[package]] +name = "miniz_oxide" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b63fbc4a50860e98e7b2aa7804ded1db5cbc3aff9193adaff57a6931bf7c4b4c" +dependencies = [ + "adler2", + "simd-adler32", +] + +[[package]] +name = "mio" +version = "1.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "30d65c71f1ce40ab09135ce117d742b9f8a19ff91a41a8b57ed50bc2de59c427" +dependencies = [ + "libc", + "wasi", + "windows-sys 0.61.2", +] + +[[package]] +name = "nalgebra" +version = "0.35.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "adc43a60c217b0c6ff46e47f26911015ad8d2e5a8be1af668c67e370d99a4346" +dependencies = [ + "approx", + "glam 0.30.10", + "glam 0.31.1", + "glam 0.32.1", + "glam 0.33.6", + "matrixmultiply", + "nalgebra-macros", + "num-complex", + "num-rational", + "num-traits", + "simba", + "typenum", +] + +[[package]] +name = "nalgebra-macros" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "973e7178a678cfd059ccec50887658d482ce16b0aa9da3888ddeab5cd5eb4889" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "nanorand" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a51313c5820b0b02bd422f4b44776fbf47961755c74ce64afc73bfad10226c3" +dependencies = [ + "getrandom 0.2.17", +] + +[[package]] +name = "nix" +version = "0.29.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "71e2746dc3a24dd78b3cfcb7be93368c6de9963d30f43a6a73998a9cf4b17b46" +dependencies = [ + "bitflags 2.13.1", + "cfg-if", + "cfg_aliases 0.2.2", + "libc", +] + +[[package]] +name = "no-std-net" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43794a0ace135be66a25d3ae77d41b91615fb68ae937f904090203e81f755b65" + +[[package]] +name = "nom" +version = "7.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" +dependencies = [ + "memchr", + "minimal-lexical", +] + +[[package]] +name = "nonempty-collections" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e216d0e8cf9d54fa66e5780f6e1d5dc96d1c1b3c25aeba3b6758548bcbbd8b9d" +dependencies = [ + "serde", +] + +[[package]] +name = "nu-ansi-term" +version = "0.50.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7957b9740744892f114936ab4a57b3f487491bbeafaf8083688b16841a4240e5" +dependencies = [ + "windows-sys 0.61.2", +] + +[[package]] +name = "num-bigint" +version = "0.4.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c89e69e7e0f03bea5ef08013795c25018e101932225a656383bd384495ecc367" +dependencies = [ + "num-integer", + "num-traits", +] + +[[package]] +name = "num-complex" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73f88a1307638156682bada9d7604135552957b7818057dcef22705b4d509495" +dependencies = [ + "num-traits", +] + +[[package]] +name = "num-conv" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "521739c6d2bac4aa25192232afe6841231376b2b26d4d9fae5ecf8ca5772e441" + +[[package]] +name = "num-integer" +version = "0.1.47" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ce2d95d4b3734dc35aa2f45e1aa22cd416814592a4f9d9205e11affd5b8e10b" +dependencies = [ + "num-traits", +] + +[[package]] +name = "num-rational" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f83d14da390562dca69fc84082e73e548e1ad308d24accdedd2720017cb37824" +dependencies = [ + "num-bigint", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-traits" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" +dependencies = [ + "autocfg", +] + +[[package]] +name = "num_cpus" +version = "1.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91df4bbde75afed763b708b7eee1e8e7651e02d97f6d5dd763e89367e957b23b" +dependencies = [ + "hermit-abi", + "libc", +] + +[[package]] +name = "oid-registry" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "12f40cff3dde1b6087cc5d5f5d4d65712f34016a03ed60e9c08dcc392736b5b7" +dependencies = [ + "asn1-rs", +] + +[[package]] +name = "once_cell" +version = "1.21.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50" + +[[package]] +name = "openssl-probe" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c87def4c32ab89d880effc9e097653c8da5d6ef28e6b539d313baaacfbafcbe" + +[[package]] +name = "option-ext" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d" + +[[package]] +name = "owned-alloc" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "30fceb411f9a12ff9222c5f824026be368ff15dc2f13468d850c7d3f502205d6" + +[[package]] +name = "parking" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f38d5652c16fde515bb1ecef450ab0f6a219d619a7274976324d5e377f7dceba" + +[[package]] +name = "parking_lot" +version = "0.12.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93857453250e3077bd71ff98b6a65ea6621a19bb0f559a85248955ac12c45a1a" +dependencies = [ + "lock_api", + "parking_lot_core", +] + +[[package]] +name = "parking_lot_core" +version = "0.9.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2621685985a2ebf1c516881c026032ac7deafcda1a2c9b7850dc81e3dfcb64c1" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall", + "smallvec", + "windows-link", +] + +[[package]] +name = "paste" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" + +[[package]] +name = "pem" +version = "4.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d354a98a3d1251555de99e8fdd8afda05573c31b82f59063a7b0a29b5527f120" +dependencies = [ + "base64 0.23.1", + "serde_core", +] + +[[package]] +name = "percent-encoding" +version = "2.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220" + +[[package]] +name = "pest" +version = "2.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a07a60cc7a4d00c91f95c685609d1d2f79050e6804b70ebedd7650f0b839bcf" +dependencies = [ + "memchr", + "ucd-trie", +] + +[[package]] +name = "pest_derive" +version = "2.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b3a83744a5c8455b8b3e0dc5031362780a347c878bdd11584d1a8984228cc88d" +dependencies = [ + "pest", + "pest_generator", +] + +[[package]] +name = "pest_generator" +version = "2.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e0cd3451aa3de60d4b9a1e736885e4dea6b31617598026f12256ad566d63304a" +dependencies = [ + "pest", + "pest_meta", + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "pest_meta" +version = "2.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e04d3a0849e241d7dfce834c83b1c5edc8622009e8dd51a12ba1927c32f05496" +dependencies = [ + "pest", +] + +[[package]] +name = "petgraph" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8701b58ea97060d5e5b155d383a69952a60943f0e6dfe30b04c287beb0b27455" +dependencies = [ + "fixedbitset", + "hashbrown 0.15.5", + "indexmap 2.14.1", + "serde", +] + +[[package]] +name = "phf" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1562dc717473dbaa4c1f85a36410e03c047b2e7df7f45ee938fbef64ae7fadf" +dependencies = [ + "phf_macros", + "phf_shared", + "serde", +] + +[[package]] +name = "phf_generator" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "135ace3a761e564ec88c03a77317a7c6b80bb7f7135ef2544dbe054243b89737" +dependencies = [ + "fastrand", + "phf_shared", +] + +[[package]] +name = "phf_macros" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "812f032b54b1e759ccd5f8b6677695d5268c588701effba24601f6932f8269ef" +dependencies = [ + "phf_generator", + "phf_shared", + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "phf_shared" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e57fef6bc5981e38c2ce2d63bfa546861309f875b8a75f092d1d54ae2d64f266" +dependencies = [ + "siphasher", +] + +[[package]] +name = "pin-project-lite" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a89322df9ebe1c1578d689c92318e070967d1042b512afbe49518723f4e6d5cd" + +[[package]] +name = "pnet_base" +version = "0.35.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ffc190d4067df16af3aba49b3b74c469e611cad6314676eaf1157f31aa0fb2f7" +dependencies = [ + "no-std-net", +] + +[[package]] +name = "pnet_datalink" +version = "0.35.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e79e70ec0be163102a332e1d2d5586d362ad76b01cec86f830241f2b6452a7b7" +dependencies = [ + "ipnetwork", + "libc", + "pnet_base", + "pnet_sys", + "winapi", +] + +[[package]] +name = "pnet_sys" +version = "0.35.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d4643d3d4db6b08741050c2f3afa9a892c4244c085a72fcda93c9c2c9a00f4b" +dependencies = [ + "libc", + "winapi", +] + +[[package]] +name = "portable-atomic" +version = "1.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05c8b63e8d9609db387f0324918f81d68fe27748f084ef092fb35954d0539a85" + +[[package]] +name = "portable-atomic-util" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2a106d1259c23fac8e543272398ae0e3c0b8d33c88ed73d0cc71b0f1d902618" +dependencies = [ + "portable-atomic", +] + +[[package]] +name = "potential_utf" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d83eb9bc6d8e5cf568e7a1101d60ee05e81ed50ea106026f3d18deeb046d7661" +dependencies = [ + "zerovec", +] + +[[package]] +name = "powerfmt" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" + +[[package]] +name = "ppv-lite86" +version = "0.2.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9" +dependencies = [ + "zerocopy", +] + +[[package]] +name = "prettyplease" +version = "0.2.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "479ca8adacdd7ce8f1fb39ce9ecccbfe93a3f1344b3d0d97f20bc0196208f62b" +dependencies = [ + "proc-macro2", + "syn 2.0.119", +] + +[[package]] +name = "proc-macro-crate" +version = "3.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e67ba7e9b2b56446f1d419b1d807906278ffa1a658a8a5d8a39dcb1f5a78614f" +dependencies = [ + "toml_edit", +] + +[[package]] +name = "proc-macro-error-attr3" +version = "3.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e564d14133360e1ae169ffde5da25881b5fa47261665b8e5713c212c27799da" +dependencies = [ + "proc-macro2", + "quote", +] + +[[package]] +name = "proc-macro-error3" +version = "3.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f0d4471b3436c22106b21913b1dda531558918ae9b7ec55d58aa84b43552233" +dependencies = [ + "proc-macro-error-attr3", + "proc-macro2", + "quote", + "syn 3.0.6", +] + +[[package]] +name = "proc-macro2" +version = "1.0.107" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "985e7ec9bb745e6ce6535b544d84d6cd6f7ad8bd711c398938ae983b91a766d9" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "prometheus-client" +version = "0.24.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cca3d75b4566b9a29fe1ed623587fb058e826eb329a0be4b7c4da1ebb2d7a6ca" +dependencies = [ + "dtoa", + "itoa", + "parking_lot", + "prometheus-client-derive-encode", +] + +[[package]] +name = "prometheus-client-derive-encode" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9adf1691c04c0a5ff46ff8f262b58beb07b0dbb61f96f9f54f6cbd82106ed87f" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "quinn" +version = "0.11.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c1a41e437b6bbd489372cd4971de128e85c855f56c57f283d20ff016cf7c0a8" +dependencies = [ + "bytes", + "cfg_aliases 0.2.2", + "pin-project-lite", + "quinn-proto", + "quinn-udp", + "rustc-hash", + "rustls", + "socket2 0.6.5", + "thiserror", + "tokio", + "tracing", + "web-time", +] + +[[package]] +name = "quinn-proto" +version = "0.11.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "04759210543be93709136e28212294a659ef5001836ff4eab4d663e4529bba83" +dependencies = [ + "bytes", + "fastbloom", + "getrandom 0.4.3", + "lru-slab", + "rand 0.10.2", + "rand_pcg", + "ring", + "rustc-hash", + "rustls", + "rustls-pki-types", + "rustls-platform-verifier", + "slab", + "thiserror", + "tinyvec", + "tracing", + "web-time", +] + +[[package]] +name = "quinn-udp" +version = "0.5.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "35a133f956daabe89a61a685c2649f13d82d5aa4bd5d12d1277e1072a21c0694" +dependencies = [ + "cfg_aliases 0.2.2", + "libc", + "once_cell", + "socket2 0.6.5", + "tracing", + "windows-sys 0.61.2", +] + +[[package]] +name = "quote" +version = "1.0.47" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fbf4db142a473a8d80c26bbf18454ed458bf8d26c8219c331daecfdbd079001" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "r-efi" +version = "5.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" + +[[package]] +name = "r-efi" +version = "6.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8dcc9c7d52a811697d2151c701e0d08956f92b0e24136cf4cf27b57a6a0d9bf" + +[[package]] +name = "rand" +version = "0.8.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e058c7de0b26af77780c769414d6257830bb240f3c38477dbc2c16e5f54d6d4c" +dependencies = [ + "libc", + "rand_chacha", + "rand_core 0.6.4", +] + +[[package]] +name = "rand" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7f5fa3a058cd35567ef9bfa5e75732bee0f9e4c55fa90477bef2dfcdbc4be80" +dependencies = [ + "chacha20", + "getrandom 0.4.3", + "rand_core 0.10.1", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core 0.6.4", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom 0.2.17", +] + +[[package]] +name = "rand_core" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "63b8176103e19a2643978565ca18b50549f6101881c443590420e4dc998a3c69" + +[[package]] +name = "rand_pcg" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "caa0f4137e1c0a72f4c651489402276c8e8e1cf081f3b0ba156d2cbeef09e86a" +dependencies = [ + "rand_core 0.10.1", +] + +[[package]] +name = "rawpointer" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60a357793950651c4ed0f3f52338f53b2f809f32d83a07f72909fa13e4c6c1e3" + +[[package]] +name = "rayon" +version = "1.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fb39b166781f92d482534ef4b4b1b2568f42613b53e5b6c160e24cfbfa30926d" +dependencies = [ + "either", + "rayon-core", +] + +[[package]] +name = "rayon-core" +version = "1.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22e18b0f0062d30d4230b2e85ff77fdfe4326feb054b9783a3460d8435c8ab91" +dependencies = [ + "crossbeam-deque", + "crossbeam-utils", +] + +[[package]] +name = "rcgen" +version = "0.14.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8774e05a7d0de114588e6a28fe7e71694b82614ed569d86d8b389dfbc98b8ad8" +dependencies = [ + "pem", + "ring", + "rustls-pki-types", + "time", + "x509-parser", + "yasna", +] + +[[package]] +name = "re_cdr" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bba10c21433b597481f366b978cdf2617e56785b38cb0dcc3833c6b8ad7e061a" +dependencies = [ + "bytemuck", + "byteorder", + "serde", + "thiserror", +] + +[[package]] +name = "reading-processor" +version = "0.1.0" +dependencies = [ + "dimos-module", + "story-messages-messages", + "tokio", + "tracing", +] + +[[package]] +name = "redox_syscall" +version = "0.5.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed2bf2547551a7053d6fdfafda3f938979645c44812fbfcda098faae3f1a362d" +dependencies = [ + "bitflags 2.13.1", +] + +[[package]] +name = "redox_users" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4e608c6638b9c18977b00b475ac1f28d14e84b27d8d42f70e0bf1e3dec127ac" +dependencies = [ + "getrandom 0.2.17", + "libredox", + "thiserror", +] + +[[package]] +name = "ref-cast" +version = "1.0.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e440fb4e4b4147295338efb76001ab9e4efc0e5839df2c47fc5ac2381d365c3" +dependencies = [ + "ref-cast-impl", +] + +[[package]] +name = "ref-cast-impl" +version = "1.0.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92ecd8964f8453721699a1ed72037b0db49ce2f5a5138486ee89bed6f67cdf3a" +dependencies = [ + "proc-macro2", + "quote", + "syn 3.0.6", +] + +[[package]] +name = "regex" +version = "1.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f020237b6c8eed93db2e2cb53c00c60a8e1bc73da7d073199a1180401450218d" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.4.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ad8553b9b26413251cbf30e620595c7a41b3887f03da04579c0e6b0d6a06b4b2" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.8.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6f6ff9a378485b298a5286656da665ba74413d36db0979633275d2e708145d4" + +[[package]] +name = "ring" +version = "0.17.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4689e6c2294d81e88dc6261c768b63bc4fcdb852be6d1352498b114f61383b7" +dependencies = [ + "cc", + "cfg-if", + "getrandom 0.2.17", + "libc", + "untrusted", + "windows-sys 0.52.0", +] + +[[package]] +name = "ringbuffer-spsc" +version = "0.1.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8d3e7aa0a681b232e7cd7f856a53b10603df88ca74b79a8d8088845185492e35" +dependencies = [ + "array-init", + "crossbeam", +] + +[[package]] +name = "rlimit" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7043b63bd0cd1aaa628e476b80e6d4023a3b50eb32789f2728908107bd0c793a" +dependencies = [ + "libc", +] + +[[package]] +name = "ron" +version = "0.12.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81116b9531d61eabc41aeb228e4b6b2435bcca3233b98cf3b3077d4e6e9debb3" +dependencies = [ + "bitflags 2.13.1", + "once_cell", + "serde", + "serde_derive", + "typeid", + "unicode-ident", +] + +[[package]] +name = "ros2msg" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2fe291be5cb6d4b8e6bf9c9de80c40bd1cb09ecac50deafa2fdcae0027e04988" +dependencies = [ + "heck", + "pest", + "pest_derive", + "prettyplease", + "proc-macro2", + "quote", + "regex", + "syn 2.0.119", + "thiserror", +] + +[[package]] +name = "rustc-hash" +version = "2.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6b1e7f9a428571be2dc5bc0505c13fb6bf936822b894ec87abf8a08a4e51742d" + +[[package]] +name = "rustc_version" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92" +dependencies = [ + "semver", +] + +[[package]] +name = "rusticata-macros" +version = "4.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "faf0c4a6ece9950b9abdb62b1cfcf2a68b3b67a10ba445b3bb85be2a293d0632" +dependencies = [ + "nom", +] + +[[package]] +name = "rustls" +version = "0.23.43" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0283386ce02abc0151e1761d08802dfe86c173b0b494af5cbc086574e453da06" +dependencies = [ + "log", + "once_cell", + "ring", + "rustls-pki-types", + "rustls-webpki", + "subtle", + "zeroize", +] + +[[package]] +name = "rustls-native-certs" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dab5152771c58876a2146916e53e35057e1a4dfa2b9df0f0305b07f611fdea4d" +dependencies = [ + "openssl-probe", + "rustls-pki-types", + "schannel", + "security-framework", +] + +[[package]] +name = "rustls-pemfile" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dce314e5fee3f39953d46bb63bb8a46d40c2f8fb7cc5a3b6cab2bde9721d6e50" +dependencies = [ + "rustls-pki-types", +] + +[[package]] +name = "rustls-pki-types" +version = "1.15.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2f4925028c7eb5d1fcdaf196971378ed9d2c1c4efc7dc5d011256f76c99c0a96" +dependencies = [ + "web-time", + "zeroize", +] + +[[package]] +name = "rustls-platform-verifier" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26d1e2536ce4f35f4846aa13bff16bd0ff40157cdb14cc056c7b14ba41233ba0" +dependencies = [ + "core-foundation", + "core-foundation-sys", + "jni", + "log", + "once_cell", + "rustls", + "rustls-native-certs", + "rustls-platform-verifier-android", + "rustls-webpki", + "security-framework", + "security-framework-sys", + "webpki-root-certs", + "windows-sys 0.61.2", +] + +[[package]] +name = "rustls-platform-verifier-android" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f87165f0995f63a9fbeea62b64d10b4d9d8e78ec6d7d51fb2125fda7bb36788f" + +[[package]] +name = "rustls-webpki" +version = "0.103.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3c3cf1d8b1e7d4927e2d154c3fcb02979afb9939629c62cd9048d4f07b60ac2" +dependencies = [ + "ring", + "rustls-pki-types", + "untrusted", +] + +[[package]] +name = "rustversion" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf54715a573b99ac80df0bc206da022bcd442c974952c7b9720069370852e21f" + +[[package]] +name = "ryu" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9774ba4a74de5f7b1c1451ed6cd5285a32eddb5cccb8cc655a4e50009e06477f" + +[[package]] +name = "safe_arch" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42c6efa15875e6ecb39ca61fb0b0c1a40b84fac5a5ffe71eef7d1000c8eb3f5f" +dependencies = [ + "bytemuck", +] + +[[package]] +name = "same-file" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "schannel" +version = "0.1.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91c1b7e4904c873ef0710c1f407dde2e6287de2bebc1bbbf7d430bb7cbffd939" +dependencies = [ + "windows-sys 0.61.2", +] + +[[package]] +name = "schemars" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4cd191f9397d57d581cddd31014772520aa448f65ef991055d7f61582c65165f" +dependencies = [ + "dyn-clone", + "ref-cast", + "serde", + "serde_json", +] + +[[package]] +name = "schemars" +version = "1.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "687274d293b6cdc6e73e0fee520bf2049650090d7164f87672d212a3c530cf4a" +dependencies = [ + "dyn-clone", + "either", + "ref-cast", + "schemars_derive", + "serde", + "serde_json", +] + +[[package]] +name = "schemars_derive" +version = "1.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d98c67716b46af2f0b8cf752abc930f6f9aecfbf671ecfb531db8a31dbe4e2ba" +dependencies = [ + "proc-macro2", + "quote", + "serde_derive_internals", + "syn 3.0.6", +] + +[[package]] +name = "scopeguard" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" + +[[package]] +name = "secrecy" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9bd1c54ea06cfd2f6b63219704de0b9b4f72dcc2b8fdef820be6cd799780e91e" +dependencies = [ + "serde", + "zeroize", +] + +[[package]] +name = "security-framework" +version = "3.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7f4bc775c73d9a02cde8bf7b2ec4c9d12743edf609006c7facc23998404cd1d" +dependencies = [ + "bitflags 2.13.1", + "core-foundation", + "core-foundation-sys", + "libc", + "security-framework-sys", +] + +[[package]] +name = "security-framework-sys" +version = "2.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ce2691df843ecc5d231c0b14ece2acc3efb62c0a398c7e1d875f3983ce020e3" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "semver" +version = "1.0.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a7852d02fc848982e0c167ef163aaff9cd91dc640ba85e263cb1ce46fae51cd" + +[[package]] +name = "serde" +version = "1.0.229" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4148590afebada386688f18773da617792bf2ef03ffc1e4cbd2b1d45b023e0ba" +dependencies = [ + "serde_core", + "serde_derive", +] + +[[package]] +name = "serde-big-array" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11fc7cc2c76d73e0f27ee52abbd64eec84d46f370c88371120433196934e4b7f" +dependencies = [ + "serde", +] + +[[package]] +name = "serde_core" +version = "1.0.229" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67dca2c9c51e58a4791a4b1ed58308b39c64224d349a935ab5039aa360942a48" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.229" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7a5d71263a5a7d47b41f6b3f06ba276f10cc18b0931f1799f710578e2309348" +dependencies = [ + "proc-macro2", + "quote", + "syn 3.0.6", +] + +[[package]] +name = "serde_derive_internals" +version = "0.30.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f852137cce035d6a4df67ccce505ff6b3e9fd3a10e3e52b24dc71e650bb1a9bd" +dependencies = [ + "proc-macro2", + "quote", + "syn 3.0.6", +] + +[[package]] +name = "serde_json" +version = "1.0.151" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c841b55ecdae098c80dcae9cf767f6f8a0c2cdb3416bbef72181df4d0fe73f14" +dependencies = [ + "indexmap 2.14.1", + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + +[[package]] +name = "serde_spanned" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6662b5879511e06e8999a8a235d848113e942c9124f211511b16466ee2995f26" +dependencies = [ + "serde_core", +] + +[[package]] +name = "serde_with" +version = "3.22.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee78f1fbe43ac4a0e47aadb3dbd357b69eb0d3793e948624cd03dd2750ab1c0a" +dependencies = [ + "base64 0.22.1", + "bs58", + "chrono", + "hex", + "indexmap 1.9.3", + "indexmap 2.14.1", + "jiff", + "schemars 0.9.0", + "schemars 1.2.2", + "serde_core", + "serde_json", + "serde_with_macros", + "time", +] + +[[package]] +name = "serde_with_macros" +version = "3.22.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8705578779c2b6bd90d84d66eb2e206b708b1a4d7b9f17641b293545bf1c7e46" +dependencies = [ + "darling", + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "serde_yaml" +version = "0.9.34+deprecated" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a8b1a1a2ebf674015cc02edccce75287f1a0130d394307b36743c2f5d504b47" +dependencies = [ + "indexmap 2.14.1", + "itoa", + "ryu", + "serde", + "unsafe-libyaml", +] + +[[package]] +name = "sha2-const-stable" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f179d4e11094a893b82fff208f74d448a7512f99f5a0acbd5c679b705f83ed9" + +[[package]] +name = "sha3" +version = "0.10.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77fd7028345d415a4034cf8777cd4f8ab1851274233b45f84e3d955502d93874" +dependencies = [ + "digest", + "keccak", +] + +[[package]] +name = "sharded-slab" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6" +dependencies = [ + "lazy_static", +] + +[[package]] +name = "shellexpand" +version = "3.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32824fab5e16e6c4d86dc1ba84489390419a39f97699852b66480bb87d297ed8" +dependencies = [ + "dirs", +] + +[[package]] +name = "shlex" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8fadd59c855ef2080decdef8ff161eb6661b86933c9d82e5ba29dc602a55aba" + +[[package]] +name = "signal-hook-registry" +version = "1.4.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4db69cba1110affc0e9f7bcd48bbf87b3f4fc7c61fc9155afd4c469eb3d6c1b" +dependencies = [ + "errno", + "libc", +] + +[[package]] +name = "simba" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1a7200d82ff1c7b4235efd12f11e2537a402c91cf83a5cb97ce80eef787fde7" +dependencies = [ + "approx", + "num-complex", + "num-traits", + "wide", +] + +[[package]] +name = "simd-adler32" +version = "0.3.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3a219298ac11a56ea9a6d2120044824d6f01aeb034955e7af7bc16858527deea" + +[[package]] +name = "simd_cesu8" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11031e251abf8611c80f460e19dbdeb54a66db918e49c65a7065b46ac7aec520" +dependencies = [ + "rustc_version", + "simdutf8", +] + +[[package]] +name = "simdutf8" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3a9fe34e3e7a50316060351f37187a3f546bce95496156754b601a5fa71b76e" + +[[package]] +name = "siphasher" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ee5873ec9cce0195efcb7a4e9507a04cd49aec9c83d0389df45b1ef7ba2e649" + +[[package]] +name = "slab" +version = "0.4.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c790de23124f9ab44544d7ac05d60440adc586479ce501c1d6d7da3cd8c9cf5" + +[[package]] +name = "smallvec" +version = "1.15.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ed6a63f02c8539c91a8685a86f4099661ba3da017932f6ebbea6de3f0fa7c90" + +[[package]] +name = "socket2" +version = "0.5.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e22376abed350d73dd1cd119b57ffccad95b4e585a7cda43e286245ce23c0678" +dependencies = [ + "libc", + "windows-sys 0.52.0", +] + +[[package]] +name = "socket2" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3d1e2c7f27f8d4cb10542a02c49005dbd6e93095799d6f3be745fae9f8fedd4" +dependencies = [ + "libc", + "windows-sys 0.61.2", +] + +[[package]] +name = "spin" +version = "0.9.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3763264f6b73151db08c50ff20d7d8a0b8796e021cdea7ceedad07b80155fa0e" +dependencies = [ + "lock_api", +] + +[[package]] +name = "spin" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "023a211cb3138dbc438680b32560ad89f699977624c9f8dbb95a47d5b4c07dd3" + +[[package]] +name = "stabby" +version = "72.1.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d53d2428934c46277fafd2d41e39357595aa1e47954c75db2b14ed90632f3cc" +dependencies = [ + "rustversion", + "stabby-abi", +] + +[[package]] +name = "stabby-abi" +version = "72.1.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f375eae680bb54203ee5e47d4cd2ae7b79c0a79ed90919279f38f500ad53f190" +dependencies = [ + "rustc_version", + "rustversion", + "sha2-const-stable", + "stabby-macros", +] + +[[package]] +name = "stabby-macros" +version = "72.1.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea664671a576c5f7e32fee291ac123d82af5e92b0689beb3555347c00c76eef1" +dependencies = [ + "proc-macro-crate", + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "stable_deref_trait" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596" + +[[package]] +name = "static_assertions" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" + +[[package]] +name = "static_init" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8bae1df58c5fea7502e8e352ec26b5579f6178e1fdb311e088580c980dee25ed" +dependencies = [ + "bitflags 1.3.2", + "cfg_aliases 0.2.2", + "libc", + "parking_lot", + "parking_lot_core", + "static_init_macro", + "winapi", +] + +[[package]] +name = "static_init_macro" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1389c88ddd739ec6d3f8f83343764a0e944cd23cfbf126a9796a714b0b6edd6f" +dependencies = [ + "cfg_aliases 0.1.1", + "memchr", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "story-messages-messages" +version = "0.1.0" +dependencies = [ + "dimos-generated-messages", + "heapless", + "re_cdr", + "ros2msg", + "serde", + "serde-big-array", +] + +[[package]] +name = "strsim" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" + +[[package]] +name = "subtle" +version = "2.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" + +[[package]] +name = "syn" +version = "1.0.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "syn" +version = "2.0.119" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "872831b642d1a07999a962a351ed35b955ea2cfc8f3862091e2a240a84f17297" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "syn" +version = "3.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8593e8e72159ed2257d083c7a454a85cbf854f37a0966d8d483aff8c8a3ebcee" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "synstructure" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "talc" +version = "4.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a3ae828aa394de34c7de08f522d1b86bd1c182c668d27da69caadda00590f26d" + +[[package]] +name = "thiserror" +version = "2.0.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09e52cb86a36cede5cb101bf8908837b3e4c6e5e59fe7fd85c23fb56200d189e" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "2.0.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe5197923287db20a58125f0bc85c062f7f2c892de97b18c356f9efb14b28524" +dependencies = [ + "proc-macro2", + "quote", + "syn 3.0.6", +] + +[[package]] +name = "thread-priority" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfe075d7053dae61ac5413a34ea7d4913b6e6207844fd726bdd858b37ff72bf5" +dependencies = [ + "bitflags 2.13.1", + "cfg-if", + "libc", + "log", + "rustversion", + "winapi", +] + +[[package]] +name = "thread_local" +version = "1.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ad99c4c6d32803332c548b1af0540b357b3f5fc0be8f6c6bfe8b2e6ae784070" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "time" +version = "0.3.55" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cdb87b95ec50ddfa440816d227a17b2ccbdda963a316a727fda0fc4334f7d134" +dependencies = [ + "deranged", + "num-conv", + "powerfmt", + "serde_core", + "time-core", + "time-macros", +] + +[[package]] +name = "time-core" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e1c906769ad99c88eaa54e728060edef082f8e358ff32030cb7c7d315e81109" + +[[package]] +name = "time-macros" +version = "0.2.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e689342a48d2ea927c87ea50cabf8594854bf940e9310208848d680d668ed85" +dependencies = [ + "num-conv", + "time-core", +] + +[[package]] +name = "tinystr" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1e27c91459209c2986af3dcf603a5a74a4368754ce37414f59acc971167f643" +dependencies = [ + "displaydoc", + "zerovec", +] + +[[package]] +name = "tinyvec" +version = "1.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb4ebadaa0af04fab11ae01eb5f9fdb5f9c5b875506e210e71c07873528baa7f" +dependencies = [ + "tinyvec_macros", +] + +[[package]] +name = "tinyvec_macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" + +[[package]] +name = "token-cell" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fb48920ae769b58126c8c93269805011c793201f95fde28b479b81a9a531bbde" +dependencies = [ + "paste", + "portable-atomic", + "rustversion", +] + +[[package]] +name = "tokio" +version = "1.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "202caea871b69668250d242070849eb495be178ed697a3e98aebce5bc81a0bed" +dependencies = [ + "bytes", + "libc", + "mio", + "pin-project-lite", + "signal-hook-registry", + "socket2 0.6.5", + "tokio-macros", + "windows-sys 0.61.2", +] + +[[package]] +name = "tokio-macros" +version = "2.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78773a2a397f451582ce068015985c33193cf6dea8b74d2a639fe457b2f07b0e" +dependencies = [ + "proc-macro2", + "quote", + "syn 3.0.6", +] + +[[package]] +name = "tokio-util" +version = "0.7.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "494815d09bf52b5548659851081238f0ca39ff638363907596da739561c62c52" +dependencies = [ + "bytes", + "futures-core", + "futures-sink", + "futures-util", + "pin-project-lite", + "tokio", +] + +[[package]] +name = "toml" +version = "0.9.12+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf92845e79fc2e2def6a5d828f0801e29a2f8acc037becc5ab08595c7d5e9863" +dependencies = [ + "indexmap 2.14.1", + "serde_core", + "serde_spanned", + "toml_datetime 0.7.5+spec-1.1.0", + "toml_parser", + "toml_writer", + "winnow 0.7.15", +] + +[[package]] +name = "toml" +version = "1.1.4+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3aace63f4bbcdfc2c965b059de67119c89c4017a70d633be6c104910f67056f5" +dependencies = [ + "indexmap 2.14.1", + "serde_core", + "serde_spanned", + "toml_datetime 1.1.1+spec-1.1.0", + "toml_parser", + "toml_writer", + "winnow 1.0.4", +] + +[[package]] +name = "toml_datetime" +version = "0.7.5+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92e1cfed4a3038bc5a127e35a2d360f145e1f4b971b551a2ba5fd7aedf7e1347" +dependencies = [ + "serde_core", +] + +[[package]] +name = "toml_datetime" +version = "1.1.1+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3165f65f62e28e0115a00b2ebdd37eb6f3b641855f9d636d3cd4103767159ad7" +dependencies = [ + "serde_core", +] + +[[package]] +name = "toml_edit" +version = "0.25.13+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6975367e4d2ef766d86af01ffad14b622fecc8d4357a998fbc4deb6e9bacaf9b" +dependencies = [ + "indexmap 2.14.1", + "toml_datetime 1.1.1+spec-1.1.0", + "toml_parser", + "winnow 1.0.4", +] + +[[package]] +name = "toml_parser" +version = "1.1.3+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d38ac1cf9b95face32296c0a3ede1fdc270627c9d9c02a7274dd6d960dc4d56" +dependencies = [ + "winnow 1.0.4", +] + +[[package]] +name = "toml_writer" +version = "1.1.2+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d56353a2a665ad0f41a421187180aab746c8c325620617ad883a99a1cbe66d2" + +[[package]] +name = "tracing" +version = "0.1.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "63e71662fa4b2a2c3a26f570f037eb95bb1f85397f3cd8076caed2f026a6d100" +dependencies = [ + "log", + "pin-project-lite", + "tracing-attributes", + "tracing-core", +] + +[[package]] +name = "tracing-attributes" +version = "0.1.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7490cfa5ec963746568740651ac6781f701c9c5ea257c58e057f3ba8cf69e8da" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "tracing-core" +version = "0.1.36" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db97caf9d906fbde555dd62fa95ddba9eecfd14cb388e4f491a66d74cd5fb79a" +dependencies = [ + "once_cell", + "valuable", +] + +[[package]] +name = "tracing-log" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee855f1f400bd0e5c02d150ae5de3840039a3f54b025156404e34c23c03f47c3" +dependencies = [ + "log", + "once_cell", + "tracing-core", +] + +[[package]] +name = "tracing-serde" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "704b1aeb7be0d0a84fc9828cae51dab5970fee5088f83d1dd7ee6f6246fc6ff1" +dependencies = [ + "serde", + "tracing-core", +] + +[[package]] +name = "tracing-subscriber" +version = "0.3.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb7f578e5945fb242538965c2d0b04418d38ec25c79d160cd279bf0731c8d319" +dependencies = [ + "matchers", + "nu-ansi-term", + "once_cell", + "regex-automata", + "serde", + "serde_json", + "sharded-slab", + "smallvec", + "thread_local", + "tracing", + "tracing-core", + "tracing-log", + "tracing-serde", +] + +[[package]] +name = "twox-hash" +version = "1.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97fee6b57c6a41524a810daee9286c02d7752c4253064d0b05472833a438f675" +dependencies = [ + "cfg-if", + "static_assertions", +] + +[[package]] +name = "typeid" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc7d623258602320d5c55d1bc22793b57daff0ec7efc270ea7d55ce1d5f5471c" + +[[package]] +name = "typenum" +version = "1.20.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6f5e870be6c3b371b77fe0ee0bafb859fa4964b4404c27de1d380043c4dda20" + +[[package]] +name = "ucd-trie" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2896d95c02a80c6d6a5d6e953d479f5ddf2dfdb6a244441010e373ac0fb88971" + +[[package]] +name = "uhlc" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b62a645e3e4e6c85b7abe49b086aa3204119431f42b6123b0070419fb6e9d24e" +dependencies = [ + "humantime", + "lazy_static", + "log", + "rand 0.8.8", + "serde", + "spin 0.10.1", +] + +[[package]] +name = "unicode-ident" +version = "1.0.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d245f478577f809a851594d02313b640fb437e0bb33866753cff937863096954" + +[[package]] +name = "unicode-xid" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" + +[[package]] +name = "unsafe-libyaml" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "673aac59facbab8a9007c7f6108d11f63b603f7cabff99fabf650fea5c32b861" + +[[package]] +name = "untrusted" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" + +[[package]] +name = "unzip-n" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b5bb2756c16fb66f80cfbf5fb0e0c09a7001e739f453c9ec241b9c8b1556fda" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "url" +version = "2.5.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff67a8a4397373c3ef660812acab3268222035010ab8680ec4215f38ba3d0eed" +dependencies = [ + "form_urlencoded", + "idna", + "percent-encoding", + "serde", +] + +[[package]] +name = "utf8_iter" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" + +[[package]] +name = "validated_struct" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "869a93e8a7286e339e1128630051d82babbcd75d585975af07b9f3327220e60e" +dependencies = [ + "json5", + "serde", + "serde_json", + "validated_struct_macros", +] + +[[package]] +name = "validated_struct_macros" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c44ce98e7227a04eeb4cf9c784109a5c9710e54849ceb4f09f8597247897f1e" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", + "unzip-n", +] + +[[package]] +name = "validator" +version = "0.21.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3d68c6633c483df6780cc5277a417c7c2d1bceee2649d06c8ab6b0fd2dd3c81" +dependencies = [ + "idna", + "regex", + "serde", + "serde_derive", + "serde_json", + "url", + "validator_derive", +] + +[[package]] +name = "validator_derive" +version = "0.20.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "240e4b81c20a1d6d50d1d7265c658dfbd204e8b9ac4d80f3c931f39462196335" +dependencies = [ + "darling", + "proc-macro-error3", + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "valuable" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba73ea9cf16a25df0c8caa16c51acb937d5712a8429db78a3ee29d5dcacd3a65" + +[[package]] +name = "vec_map" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191" + +[[package]] +name = "version_check" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" + +[[package]] +name = "walkdir" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b" +dependencies = [ + "same-file", + "winapi-util", +] + +[[package]] +name = "wasi" +version = "0.11.1+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" + +[[package]] +name = "wasip2" +version = "1.0.4+wasi-0.2.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b67efb37e106e55ce722a510d6b5f9c17f083e5fc79afc2badeb12cc313d9487" +dependencies = [ + "wit-bindgen", +] + +[[package]] +name = "wasm-bindgen" +version = "0.2.127" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b70935747edd64d89de3efa29d73789b806c15798f8e7dca4d8ac356b50ce70" +dependencies = [ + "cfg-if", + "once_cell", + "rustversion", + "wasm-bindgen-macro", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.127" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77775f8f3f7217702089053b94958f8f54061a3f663417df76e19cbdcca29bc1" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.127" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e11d33f857dc2fb11b8bc75aee111aa9cbeb12cd9f25efd3d4c2a3dd4e235284" +dependencies = [ + "bumpalo", + "proc-macro2", + "quote", + "syn 2.0.119", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.127" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ef64dbcc55df09c7e5a46182d181c2cfa3e925f3da937ea764728b4bbb9dcbf" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "web-time" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a6580f308b1fad9207618087a65c04e7a10bc77e02c8e84e9b00dd4b12fa0bb" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "webpki-root-certs" +version = "1.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b96554aa2acc8ccdb7e1c9a58a7a68dd5d13bccc69cd124cb09406db612a1c9b" +dependencies = [ + "rustls-pki-types", +] + +[[package]] +name = "webpki-roots" +version = "1.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7dcd9d09a39985f5344844e66b0c530a33843579125f23e21e9f0f220850f22a" +dependencies = [ + "rustls-pki-types", +] + +[[package]] +name = "wide" +version = "1.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8cf05ca94c9fba0c51316899caa1d1e74a064fc310a5efa7375e614343d415be" +dependencies = [ + "bytemuck", + "safe_arch", +] + +[[package]] +name = "win-sys" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b7b128a98c1cfa201b09eb49ba285887deb3cbe7466a98850eb1adabb452be5" +dependencies = [ + "windows", +] + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-util" +version = "0.1.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22" +dependencies = [ + "windows-sys 0.61.2", +] + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + +[[package]] +name = "windows" +version = "0.34.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "45296b64204227616fdbf2614cefa4c236b98ee64dfaaaa435207ed99fe7829f" +dependencies = [ + "windows_aarch64_msvc 0.34.0", + "windows_i686_gnu 0.34.0", + "windows_i686_msvc 0.34.0", + "windows_x86_64_gnu 0.34.0", + "windows_x86_64_msvc 0.34.0", +] + +[[package]] +name = "windows-core" +version = "0.62.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8e83a14d34d0623b51dce9581199302a221863196a1dde71a7663a4c2be9deb" +dependencies = [ + "windows-implement", + "windows-interface", + "windows-link", + "windows-result", + "windows-strings", +] + +[[package]] +name = "windows-implement" +version = "0.60.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "053e2e040ab57b9dc951b72c264860db7eb3b0200ba345b4e4c3b14f67855ddf" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "windows-interface" +version = "0.59.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f316c4a2570ba26bbec722032c4099d8c8bc095efccdc15688708623367e358" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "windows-link" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" + +[[package]] +name = "windows-result" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7781fa89eaf60850ac3d2da7af8e5242a5ea78d1a11c49bf2910bb5a73853eb5" +dependencies = [ + "windows-link", +] + +[[package]] +name = "windows-strings" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7837d08f69c77cf6b07689544538e017c1bfcf57e34b4c0ff58e6c2cd3b37091" +dependencies = [ + "windows-link", +] + +[[package]] +name = "windows-sys" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +dependencies = [ + "windows-targets", +] + +[[package]] +name = "windows-sys" +version = "0.61.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc" +dependencies = [ + "windows-link", +] + +[[package]] +name = "windows-targets" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" +dependencies = [ + "windows_aarch64_gnullvm", + "windows_aarch64_msvc 0.52.6", + "windows_i686_gnu 0.52.6", + "windows_i686_gnullvm", + "windows_i686_msvc 0.52.6", + "windows_x86_64_gnu 0.52.6", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc 0.52.6", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.34.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "17cffbe740121affb56fad0fc0e421804adf0ae00891205213b5cecd30db881d" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" + +[[package]] +name = "windows_i686_gnu" +version = "0.34.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2564fde759adb79129d9b4f54be42b32c89970c18ebf93124ca8870a498688ed" + +[[package]] +name = "windows_i686_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" + +[[package]] +name = "windows_i686_msvc" +version = "0.34.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9cd9d32ba70453522332c14d38814bceeb747d80b3958676007acadd7e166956" + +[[package]] +name = "windows_i686_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.34.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfce6deae227ee8d356d19effc141a509cc503dfd1f850622ec4b0f84428e1f4" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.34.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d19538ccc21819d01deaf88d6a17eae6596a12e9aafdbb97916fb49896d89de9" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" + +[[package]] +name = "winnow" +version = "0.7.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df79d97927682d2fd8adb29682d1140b343be4ac0f08fd68b7765d9c059d3945" + +[[package]] +name = "winnow" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23b97319f7b8343df12cc98938e5c3eb436064524c8d2b4e30a1d3a36eecdf81" +dependencies = [ + "memchr", +] + +[[package]] +name = "wit-bindgen" +version = "0.57.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ebf944e87a7c253233ad6766e082e3cd714b5d03812acc24c318f549614536e" + +[[package]] +name = "writeable" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ad82d2a33cdc9674dc7465672f271e096168fcdbe0f799d9e6db8c5892679dc" + +[[package]] +name = "x509-parser" +version = "0.18.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d43b0f71ce057da06bc0851b23ee24f3f86190b07203dd8f567d0b706a185202" +dependencies = [ + "asn1-rs", + "data-encoding", + "der-parser", + "lazy_static", + "nom", + "oid-registry", + "ring", + "rusticata-macros", + "thiserror", + "time", +] + +[[package]] +name = "yasna" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5f6765e852b9b4dc8e2a76843e4d64d1cea8e79bcde0b6901aea8e7c7f08282" +dependencies = [ + "bit-vec", + "time", +] + +[[package]] +name = "yoke" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "709fe23a0424b6a435d82152b1bd3fdfb0833487d5fa90d05d42762a9891fef5" +dependencies = [ + "stable_deref_trait", + "yoke-derive", + "zerofrom", +] + +[[package]] +name = "yoke-derive" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "de844c262c8848816172cef550288e7dc6c7b7814b4ee56b3e1553f275f1858e" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", + "synstructure", +] + +[[package]] +name = "zenoh" +version = "1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f7ad636296bfdb8a86bbbc9bae1b6a57f0e77b715769f99885ca2ca2368c73a" +dependencies = [ + "ahash", + "arc-swap", + "async-trait", + "bytes", + "const_format", + "flate2", + "flume", + "futures", + "git-version", + "itertools", + "json5", + "lazy_static", + "nonempty-collections", + "once_cell", + "petgraph", + "phf", + "rand 0.8.8", + "rustc_version", + "serde", + "serde_json", + "socket2 0.5.10", + "tokio", + "tokio-util", + "tracing", + "uhlc", + "vec_map", + "zenoh-buffers", + "zenoh-codec", + "zenoh-collections", + "zenoh-config", + "zenoh-core", + "zenoh-keyexpr", + "zenoh-link", + "zenoh-link-commons", + "zenoh-macros", + "zenoh-plugin-trait", + "zenoh-protocol", + "zenoh-result", + "zenoh-runtime", + "zenoh-shm", + "zenoh-sync", + "zenoh-task", + "zenoh-transport", + "zenoh-util", +] + +[[package]] +name = "zenoh-buffers" +version = "1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a81e52197e18bc75587c566df732726aee6e0a1c8779d7a2ff609f461f6b1a07" +dependencies = [ + "zenoh-collections", +] + +[[package]] +name = "zenoh-codec" +version = "1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "31b792ce46854f252af31869030224c2da6bd9d72a1cd2812e29b457444a07b1" +dependencies = [ + "rand 0.8.8", + "tracing", + "uhlc", + "zenoh-buffers", + "zenoh-protocol", + "zenoh-shm", +] + +[[package]] +name = "zenoh-collections" +version = "1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42b897fae0ddce178e3e58d3bb9ca131dd2a301dd869ebded37d9e1f3784aac0" +dependencies = [ + "ahash", +] + +[[package]] +name = "zenoh-config" +version = "1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b39224e3029571e0572f88590eb9078bcd60dedc6381ad1a5c8ad5fb7a474bf" +dependencies = [ + "json5", + "nonempty-collections", + "num_cpus", + "secrecy", + "serde", + "serde_json", + "serde_with", + "serde_yaml", + "toml 0.9.12+spec-1.1.0", + "tracing", + "uhlc", + "validated_struct", + "zenoh-core", + "zenoh-keyexpr", + "zenoh-macros", + "zenoh-protocol", + "zenoh-result", + "zenoh-util", +] + +[[package]] +name = "zenoh-core" +version = "1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9335e8f6509fcbec68a073372c13a69ba90c3a284a86427257607d75586b6344" +dependencies = [ + "lazy_static", + "tokio", + "zenoh-result", + "zenoh-runtime", +] + +[[package]] +name = "zenoh-crypto" +version = "1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b496e8c984260c4d80ce58b42956081dc8656f0b875766e5ae0f8e39510fdee" +dependencies = [ + "aes", + "hmac", + "rand 0.8.8", + "rand_chacha", + "sha3", + "zenoh-result", +] + +[[package]] +name = "zenoh-keyexpr" +version = "1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af891f8d9f52c3e8617712b65b08fa9ae02f1f1b57e2739ff194bb65df1255df" +dependencies = [ + "getrandom 0.2.17", + "hashbrown 0.16.1", + "keyed-set", + "rand 0.8.8", + "schemars 1.2.2", + "serde", + "token-cell", + "zenoh-result", +] + +[[package]] +name = "zenoh-link" +version = "1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "04f796c9df0ef7736d140363507498d8c5d0acf621c158113f122aa992979d3d" +dependencies = [ + "zenoh-config", + "zenoh-link-commons", + "zenoh-link-tcp", + "zenoh-link-udp", + "zenoh-protocol", + "zenoh-result", +] + +[[package]] +name = "zenoh-link-commons" +version = "1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4dd110109f4f89450491bd8942152020f632eb86d8fac10349a186185f654873" +dependencies = [ + "async-trait", + "base64 0.22.1", + "bytes", + "flume", + "futures", + "quinn", + "quinn-proto", + "rcgen", + "rustls", + "rustls-pemfile", + "rustls-pki-types", + "rustls-webpki", + "secrecy", + "serde", + "socket2 0.5.10", + "time", + "tokio", + "tokio-util", + "tracing", + "webpki-roots", + "x509-parser", + "zenoh-buffers", + "zenoh-codec", + "zenoh-config", + "zenoh-core", + "zenoh-protocol", + "zenoh-result", + "zenoh-runtime", + "zenoh-util", +] + +[[package]] +name = "zenoh-link-quic_datagram" +version = "1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97b2cddd28955877b7eceedfaf09c801aac31ab8f0cac32c936f31358f5af133" +dependencies = [ + "async-trait", + "rustls-webpki", + "time", + "tokio-util", + "tracing", + "zenoh-core", + "zenoh-link-commons", + "zenoh-protocol", + "zenoh-result", +] + +[[package]] +name = "zenoh-link-tcp" +version = "1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4801cc6fb608b5069f3ea6b82484c5f727019764e90e14838fe6930a9dffd9a1" +dependencies = [ + "async-trait", + "socket2 0.5.10", + "tokio", + "tokio-util", + "tracing", + "zenoh-config", + "zenoh-core", + "zenoh-link-commons", + "zenoh-protocol", + "zenoh-result", +] + +[[package]] +name = "zenoh-link-udp" +version = "1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6785a0b6f0b94131c002a8358aaef3eb99f5ab0e0cd444f28d1f1fac38bd4091" +dependencies = [ + "async-trait", + "libc", + "socket2 0.5.10", + "tokio", + "tokio-util", + "tracing", + "windows-sys 0.61.2", + "zenoh-buffers", + "zenoh-core", + "zenoh-link-commons", + "zenoh-link-quic_datagram", + "zenoh-protocol", + "zenoh-result", + "zenoh-sync", + "zenoh-util", +] + +[[package]] +name = "zenoh-macros" +version = "1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c813ccde166cf0527402d46615257e0d152140e66f8ecd685721f9399251407" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", + "zenoh-keyexpr", +] + +[[package]] +name = "zenoh-plugin-trait" +version = "1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95cd9d698675a5b2f3e958a35df56f6d60f0388669158055b436c0cbe5357ad8" +dependencies = [ + "git-version", + "libloading", + "serde", + "stabby", + "tracing", + "zenoh-config", + "zenoh-keyexpr", + "zenoh-macros", + "zenoh-result", + "zenoh-util", +] + +[[package]] +name = "zenoh-protocol" +version = "1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce5505e2569421d3cb6792d4b3d9a6589d04add3bf34c0a7c37c03c2573b79ad" +dependencies = [ + "const_format", + "rand 0.8.8", + "serde", + "uhlc", + "zenoh-buffers", + "zenoh-keyexpr", + "zenoh-macros", + "zenoh-result", +] + +[[package]] +name = "zenoh-result" +version = "1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf23203517d6dfe04393c42053093c7cffd9e385015e21c85dafaff9a342cccf" +dependencies = [ + "anyhow", +] + +[[package]] +name = "zenoh-runtime" +version = "1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ddf72c7310a090b0b22496649274661de8a17ca0d0674af8f72f184a3ed78664" +dependencies = [ + "lazy_static", + "ron", + "serde", + "tokio", + "tracing", + "zenoh-macros", + "zenoh-result", +] + +[[package]] +name = "zenoh-shm" +version = "1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8f49ff9d36be3fdeada23103c5ba10d6e7159269bd8b07fb744448005fb5734" +dependencies = [ + "advisory-lock", + "async-trait", + "buddy_system_allocator", + "crossbeam-channel", + "crossbeam-queue", + "nix", + "num-traits", + "rand 0.8.8", + "rlimit", + "stabby", + "static_assertions", + "static_init", + "talc", + "thread-priority", + "tokio", + "tracing", + "win-sys", + "winapi", + "zenoh-buffers", + "zenoh-core", + "zenoh-macros", + "zenoh-result", +] + +[[package]] +name = "zenoh-stats" +version = "1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f610d551359e0d8864138d4c4c11ed8e3c9f6991717f4eef198ab323b4ff01f4" +dependencies = [ + "ahash", + "prometheus-client", + "serde_json", + "smallvec", + "zenoh-keyexpr", + "zenoh-protocol", +] + +[[package]] +name = "zenoh-sync" +version = "1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9792a8fa9b0f30ebabd3e6b278441178b6832462e959388aa18f92a93527935b" +dependencies = [ + "arc-swap", + "event-listener", + "futures", + "tokio", + "zenoh-buffers", + "zenoh-collections", + "zenoh-core", +] + +[[package]] +name = "zenoh-task" +version = "1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fbb419757b0c6e824bebf34959302e6edf5a7caea4e725de88007a56f3ba4d4d" +dependencies = [ + "futures", + "tokio", + "tokio-util", + "tracing", + "zenoh-core", + "zenoh-runtime", +] + +[[package]] +name = "zenoh-transport" +version = "1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc431ec1c066d7047c601ae4b4d4a359882c5464cd9c4ff3fe905ff6e10017af" +dependencies = [ + "async-trait", + "crossbeam-utils", + "flume", + "futures", + "lazy_static", + "lockfree", + "lz4_flex", + "rand 0.8.8", + "ringbuffer-spsc", + "serde", + "sha3", + "static_init", + "tokio", + "tokio-util", + "tracing", + "zenoh-buffers", + "zenoh-codec", + "zenoh-config", + "zenoh-core", + "zenoh-crypto", + "zenoh-link", + "zenoh-link-commons", + "zenoh-protocol", + "zenoh-result", + "zenoh-runtime", + "zenoh-shm", + "zenoh-stats", + "zenoh-sync", + "zenoh-task", + "zenoh-util", +] + +[[package]] +name = "zenoh-util" +version = "1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f99b13044636f453bcb49ca520db4b1400c8e444fdf578e63a1aad0ed9004e0" +dependencies = [ + "async-trait", + "const_format", + "flume", + "home", + "humantime", + "lazy_static", + "libc", + "libloading", + "pnet_datalink", + "schemars 1.2.2", + "serde", + "serde_json", + "shellexpand", + "tokio", + "tracing", + "tracing-subscriber", + "winapi", + "zenoh-core", + "zenoh-result", +] + +[[package]] +name = "zerocopy" +version = "0.8.56" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "556764e583adb45a9f8d413c2a147fa7e8d821e48e12b14fd560b607998b75eb" +dependencies = [ + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.8.56" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2ab42fc20575779bd240faa45f94a74256f755c0fa9e89f0ede20d91d0cdfc1" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "zerofrom" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ec05a11813ea801ff6d75110ad09cd0824ddba17dfe17128ea0d5f68e6c5272" +dependencies = [ + "zerofrom-derive", +] + +[[package]] +name = "zerofrom-derive" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11532158c46691caf0f2593ea8358fed6bbf68a0315e80aae9bd41fbade684a1" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", + "synstructure", +] + +[[package]] +name = "zeroize" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e13c156562582aa81c60cb29407084cdb54c4164760106ab78e6c5b0858cf64e" + +[[package]] +name = "zerotrie" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ea269c3bd32f0a32c321907a2ae912ba6f4649bb0fc764a15627e99a7095a3f" +dependencies = [ + "displaydoc", + "yoke", + "zerofrom", +] + +[[package]] +name = "zerovec" +version = "0.11.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb0464e17806c1d976d5cba29399c7f08e516e279e2ba493f63123b5fca67dd8" +dependencies = [ + "yoke", + "zerofrom", + "zerovec-derive", +] + +[[package]] +name = "zerovec-derive" +version = "0.11.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34df6fc39dbd26ddc9c10e6a2984476e13acce22e64e4487636ef494369225da" +dependencies = [ + "proc-macro2", + "quote", + "syn 3.0.6", +] + +[[package]] +name = "zlib-rs" +version = "0.6.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34b31d188d9d685a4f9c7b46d6e36631b07058d2cfe190267adce54dc230bf12" + +[[package]] +name = "zmij" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b" diff --git a/examples/message-project/rust/Cargo.toml b/examples/message-project/rust/Cargo.toml new file mode 100644 index 00000000000..75868243530 --- /dev/null +++ b/examples/message-project/rust/Cargo.toml @@ -0,0 +1,15 @@ +[package] +name = "reading-processor" +version = "0.1.0" +edition = "2024" + +[workspace] + +[dependencies] +dimos-module = { path = "../sdk/rust/dimos-module" } +story-messages-messages = { path = "../build/dimos/cargo-packages/story_messages" } +tokio = { version = "1", features = ["rt-multi-thread", "macros"] } +tracing = "0.1" + +[patch.crates-io] +dimos-generated-messages = { path = "../build/dimos/cargo-packages/dimos_generated" } diff --git a/examples/message-project/rust/src/main.rs b/examples/message-project/rust/src/main.rs new file mode 100644 index 00000000000..a36b9696003 --- /dev/null +++ b/examples/message-project/rust/src/main.rs @@ -0,0 +1,38 @@ +// Copyright 2026 Dimensional Inc. +// +// 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. + +use dimos_module::{Input, Module, Output, cdr, run_with_transport}; +use story_messages_messages::story_msgs::msg::device_reading::DeviceReading; + +#[derive(Module)] +struct Processor { + #[input(decode = cdr::decode)] + processed: Input, + #[output(encode = cdr::encode)] + checked: Output, +} + +impl Processor { + async fn handle_processed(&mut self, mut message: DeviceReading) { + message.value += 1.0; + if let Err(error) = self.checked.publish(&message).await { + tracing::error!(%error, "publish failed"); + } + } +} + +#[tokio::main] +async fn main() { + run_with_transport::().await; +} diff --git a/examples/native-modules/cpp/flake.lock b/examples/native-modules/cpp/flake.lock index 0ff3a2e449c..adbcf88e1f5 100644 --- a/examples/native-modules/cpp/flake.lock +++ b/examples/native-modules/cpp/flake.lock @@ -28,11 +28,11 @@ }, "locked": { "dir": "native/cpp", - "lastModified": 1792431336, - "narHash": "sha256-W0biIt+6oH7bBHt44kV4J411Y3AUsuMkQ7OsS45BxDE=", + "lastModified": 1792432073, + "narHash": "sha256-5BgFoVp3/X5bKasI5G+f41sqVGAnZ4VPi1w3eC6+DIM=", "owner": "dimensionalOS", "repo": "dimos", - "rev": "fbccb5c45eb84a7f65413a37cba7afe3fe2d8008", + "rev": "ea1d296b163d325d2dea782c4057dbaa3b697fc4", "type": "github" }, "original": { diff --git a/packages/dimos-generated/catalog.json b/packages/dimos-generated/catalog.json index 1b39ac7c34f..8994a6eaedd 100644 --- a/packages/dimos-generated/catalog.json +++ b/packages/dimos-generated/catalog.json @@ -69,6 +69,11 @@ "vision_msgs/msg/ObjectHypothesis": "Published runtime consumer: dimos/perception/detection/type/detection2d/bbox.py", "vision_msgs/msg/ObjectHypothesisWithPose": "Published runtime consumer: dimos/perception/detection/type/detection2d/bbox.py", "vision_msgs/msg/Point2D": "Published runtime consumer: dimos/perception/detection/type/detection2d/bbox.py", - "vision_msgs/msg/Pose2D": "Published runtime consumer: dimos/perception/detection/type/detection2d/bbox.py" + "vision_msgs/msg/Pose2D": "Published runtime consumer: dimos/perception/detection/type/detection2d/bbox.py", + "dimos_msgs/msg/Contact": "DimOS runtime message contract", + "dimos_msgs/msg/Contacts": "DimOS runtime message contract", + "dimos_msgs/msg/RegionBounds": "DimOS runtime message contract", + "dimos_msgs/msg/RegionLineSegments3D": "DimOS runtime message contract", + "dimos_msgs/msg/RegionPointCloud2": "DimOS runtime message contract" } } diff --git a/packages/dimos-generated/custom/dimos_msgs/msg/Contact.msg b/packages/dimos-generated/custom/dimos_msgs/msg/Contact.msg new file mode 100644 index 00000000000..f74fc70cfd8 --- /dev/null +++ b/packages/dimos-generated/custom/dimos_msgs/msg/Contact.msg @@ -0,0 +1,7 @@ +# Copyright 2026 Dimensional Inc. +# SPDX-License-Identifier: Apache-2.0 + +# Semantic robot part and contacted scene geometry kind. +# part: trunk, lidar, leg, foot; kind: floor, wall, ceiling, clutter. +string part +string kind diff --git a/packages/dimos-generated/custom/dimos_msgs/msg/Contacts.msg b/packages/dimos-generated/custom/dimos_msgs/msg/Contacts.msg new file mode 100644 index 00000000000..7fc32d9bb9c --- /dev/null +++ b/packages/dimos-generated/custom/dimos_msgs/msg/Contacts.msg @@ -0,0 +1,6 @@ +# Copyright 2026 Dimensional Inc. +# SPDX-License-Identifier: Apache-2.0 + +# Semantic contacts at a source timestamp; published whenever the set changes. +std_msgs/Header header +Contact[] contacts diff --git a/packages/dimos-generated/custom/dimos_msgs/msg/RegionBounds.msg b/packages/dimos-generated/custom/dimos_msgs/msg/RegionBounds.msg new file mode 100644 index 00000000000..3231a6c181a --- /dev/null +++ b/packages/dimos-generated/custom/dimos_msgs/msg/RegionBounds.msg @@ -0,0 +1,10 @@ +# Copyright 2026 Dimensional Inc. +# SPDX-License-Identifier: Apache-2.0 + +# Cylinder of one map update; seed cloud/bounds pair by region_id. +std_msgs/Header header +int32 region_id +geometry_msgs/Point center +float64 radius +float64 z_min +float64 z_max diff --git a/packages/dimos-generated/custom/dimos_msgs/msg/RegionLineSegments3D.msg b/packages/dimos-generated/custom/dimos_msgs/msg/RegionLineSegments3D.msg new file mode 100644 index 00000000000..e989bba50f7 --- /dev/null +++ b/packages/dimos-generated/custom/dimos_msgs/msg/RegionLineSegments3D.msg @@ -0,0 +1,6 @@ +# Copyright 2026 Dimensional Inc. +# SPDX-License-Identifier: Apache-2.0 + +# One keyed set of weighted graph edges; an empty set clears this cell. +int32 region_id +LineSegments3D lines diff --git a/packages/dimos-generated/custom/dimos_msgs/msg/RegionPointCloud2.msg b/packages/dimos-generated/custom/dimos_msgs/msg/RegionPointCloud2.msg new file mode 100644 index 00000000000..cb358d5fe0d --- /dev/null +++ b/packages/dimos-generated/custom/dimos_msgs/msg/RegionPointCloud2.msg @@ -0,0 +1,6 @@ +# Copyright 2026 Dimensional Inc. +# SPDX-License-Identifier: Apache-2.0 + +# One keyed map cell; an empty cloud replaces/clears this cell. +int32 region_id +sensor_msgs/PointCloud2 cloud diff --git a/packages/dimos-message-project/pyproject.toml b/packages/dimos-message-project/pyproject.toml new file mode 100644 index 00000000000..913b97028b4 --- /dev/null +++ b/packages/dimos-message-project/pyproject.toml @@ -0,0 +1,13 @@ +[build-system] +requires = ["setuptools>=77", "wheel"] +build-backend = "setuptools.build_meta" + +[project] +name = "dimos-message-project" +version = "0.1.0" +description = "DimOS message project configuration and build frontends" +requires-python = ">=3.10" +dependencies = ["dimos-cdrgen==0.1.0"] + +[tool.setuptools.packages.find] +where = ["src"] diff --git a/packages/dimos-message-project/src/dimos_message_project/__init__.py b/packages/dimos-message-project/src/dimos_message_project/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/packages/dimos-message-project/src/dimos_message_project/backend.py b/packages/dimos-message-project/src/dimos_message_project/backend.py new file mode 100644 index 00000000000..830ef35770f --- /dev/null +++ b/packages/dimos-message-project/src/dimos_message_project/backend.py @@ -0,0 +1,133 @@ +# Copyright 2026 Dimensional Inc. +# +# 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. + +"""PEP 517/660 backend for standalone message projects, not the DimOS runtime.""" + +from __future__ import annotations + +from collections.abc import Iterator +from contextlib import contextmanager +import gzip +import os +from pathlib import Path +import tarfile +from typing import Any + +from setuptools import build_meta + +from dimos_cdrgen.python import write_distribution +from dimos_message_project.project import Project, prepare + + +@contextmanager +def python_project() -> Iterator[None]: + project = Project.load(Path.cwd()) + output = prepare(project, ("python",)) + dependencies = project.dependencies() + write_distribution( + output, + project.module, + (), + project.version, + dependencies=dependencies, + ) + previous = Path.cwd() + try: + os.chdir(output / "python") + yield + finally: + os.chdir(previous) + + +def get_requires_for_build_wheel(config_settings: dict[str, Any] | None = None) -> list[str]: + return [ + "setuptools>=70", + "wheel", + *Project.load(Path.cwd()).requirements(), + ] + + +get_requires_for_build_editable = get_requires_for_build_wheel + + +def get_requires_for_build_sdist(config_settings: dict[str, Any] | None = None) -> list[str]: + return [] + + +def build_wheel( + wheel_directory: str, + config_settings: dict[str, Any] | None = None, + metadata_directory: str | None = None, +) -> str: + destination = str(Path(wheel_directory).resolve()) + metadata = str(Path(metadata_directory).resolve()) if metadata_directory else None + with python_project(): + return str(build_meta.build_wheel(destination, config_settings, metadata)) + + +def build_editable( + wheel_directory: str, + config_settings: dict[str, Any] | None = None, + metadata_directory: str | None = None, +) -> str: + destination = str(Path(wheel_directory).resolve()) + metadata = str(Path(metadata_directory).resolve()) if metadata_directory else None + with python_project(): + return str(build_meta.build_editable(destination, config_settings, metadata)) + + +def prepare_metadata_for_build_wheel( + metadata_directory: str, config_settings: dict[str, Any] | None = None +) -> str: + destination = str(Path(metadata_directory).resolve()) + with python_project(): + return str(build_meta.prepare_metadata_for_build_wheel(destination, config_settings)) + + +prepare_metadata_for_build_editable = prepare_metadata_for_build_wheel + + +def build_sdist(sdist_directory: str, config_settings: dict[str, Any] | None = None) -> str: + project = Project.load(Path.cwd()) + if any("path" in spec for spec in project.dependency_specs.values()): + raise ValueError( + "Source distributions require installed, version-pinned dependencies; remove development dependency paths" + ) + name = f"{project.name.replace('-', '_')}-{project.version}" + destination = Path(sdist_directory).resolve() + destination.mkdir(parents=True, exist_ok=True) + paths = [project.root / "pyproject.toml", *sorted(project.source.rglob("*.msg"))] + if not project.internal and len(paths) == 1: + raise ValueError("Cannot package a project with no message definitions") + paths.extend( + path for path in (project.root / "README.md", project.root / "LICENSE") if path.is_file() + ) + epoch = int(os.environ.get("SOURCE_DATE_EPOCH", "0")) + with ( + (destination / f"{name}.tar.gz").open("wb") as raw, + gzip.GzipFile(filename="", mode="wb", fileobj=raw, mtime=epoch) as compressed, + tarfile.open(fileobj=compressed, mode="w") as archive, + ): + for path in paths: + if path.is_symlink() or not path.resolve().is_relative_to(project.root): + raise ValueError(f"Source file escapes the project: {path}") + info = archive.gettarinfo( + str(path), f"{name}/{path.relative_to(project.root).as_posix()}" + ) + info.uid = info.gid = 0 + info.uname = info.gname = "" + info.mtime = epoch + with path.open("rb") as stream: + archive.addfile(info, stream) + return f"{name}.tar.gz" diff --git a/packages/dimos-message-project/src/dimos_message_project/build.py b/packages/dimos-message-project/src/dimos_message_project/build.py new file mode 100644 index 00000000000..271552aec0b --- /dev/null +++ b/packages/dimos-message-project/src/dimos_message_project/build.py @@ -0,0 +1,174 @@ +# Copyright 2026 Dimensional Inc. +# +# 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. + +"""Language build frontends over the shared message-project generation plan.""" + +from __future__ import annotations + +from collections.abc import Iterator +from contextlib import contextmanager +import json +import os +from pathlib import Path +import re +import shutil +import subprocess +import sys +import tarfile + +from dimos_message_project import backend +from dimos_cdrgen.generate import generate +from dimos_cdrgen.native_build import prepare_cpp, write_cmake_toolchain +from dimos_message_project.project import LANGUAGES, Project, prepare + + +@contextmanager +def project_directory(root: Path) -> Iterator[None]: + previous = Path.cwd() + try: + os.chdir(root) + yield + finally: + os.chdir(previous) + + +def local_cargo_dependency(text: str, module: str) -> str: + """Relocate one versioned crate reference inside a local source bundle.""" + crate_name = module.replace("_", "-") + "-messages" + + def replace(match: re.Match[str]) -> str: + declaration = re.sub(r',\s*path\s*=\s*"[^"]*"', "", match.group(1)).rstrip() + return declaration + ", path = " + json.dumps("../" + module) + " }" + + return re.sub( + r"(?m)^(" + re.escape(crate_name) + r"\s*=\s*\{[^}]*?)\s*\}$", + replace, + text, + ) + + +def build_project( + project: Project, + languages: tuple[str, ...] | None = None, + *, + install: bool = False, + offline: bool = False, +) -> dict[str, str]: + selected = languages or project.languages + if not selected or any(language not in LANGUAGES for language in selected): + raise ValueError("Select python, cpp and/or rust") + if install and "python" in selected and sys.prefix == sys.base_prefix: + raise ValueError( + "Python --install requires an active virtual environment; no system install is performed" + ) + for tool in ({"cmake"} if "cpp" in selected else set()) | ( + {"cargo"} if "rust" in selected else set() + ): + if shutil.which(tool) is None: + raise ValueError( + f"Missing build tool {tool}; prepare the language toolchain before building" + ) + output = prepare(project, selected) + dist = project.root / "dist" + dist.mkdir(exist_ok=True) + state = output / "artifacts.json" + artifacts = json.loads(state.read_text()) if state.is_file() else {} + artifacts.update( + { + "schemas": str(output / "schemas.json"), + "ownership": str(output / "message-package.json"), + } + ) + dependencies = project.dependencies() + if "python" in selected: + with project_directory(project.root): + wheel = backend.build_wheel(str(dist)) + backend.build_sdist(str(dist)) + artifacts["python_wheel"] = str(dist / wheel) + if install: + subprocess.run( + [sys.executable, "-m", "pip", "install", "--no-deps", str(dist / wheel)], check=True + ) + if set(selected) - {"python"}: + output = prepare(project, selected) + if "cpp" in selected: + prefix = prepare_cpp(output, offline=offline) + artifacts["cmake_prefix"] = str(prefix) + artifacts["cmake_toolchain"] = str( + write_cmake_toolchain(prefix, output / "toolchain.cmake") + ) + if "rust" in selected: + # A relocatable local source bundle works before any registry publication. + bundle = output / "cargo-packages" + lock_path = bundle / project.module / "Cargo.lock" + previous_lock = lock_path.read_bytes() if lock_path.is_file() else None + if bundle.exists(): + shutil.rmtree(bundle) + crates = [(project.module, output), *((dep.module, dep.root) for dep in dependencies)] + for module, root in crates: + if not (root / "rust/Cargo.toml").is_file(): + manifest = json.loads((root / "message-package.json").read_text()) + available = {dep.module: dep for dep in dependencies} + required = set(manifest["dependencies"]) + pending = list(required) + while pending: + dep = available[pending.pop()] + children = json.loads((dep.root / "message-package.json").read_text())[ + "dependencies" + ] + pending.extend(set(children) - required) + required.update(children) + generated = output / "native-sources" / module + generate( + [root / "schemas"], + generated, + manifest["owned"], + module, + version=manifest["version"], + shared=True, + languages=("rust",), + dependencies=tuple(available[name] for name in sorted(required)), + ) + root = generated + target = bundle / module + shutil.copytree( + root / "rust", target, ignore=shutil.ignore_patterns("target", "Cargo.lock") + ) + manifest = target / "Cargo.toml" + text = manifest.read_text() + for dep in dependencies: + text = local_cargo_dependency(text, dep.module) + manifest.write_text(text) + cargo_manifest = bundle / project.module / "Cargo.toml" + if previous_lock is not None: + lock_path.write_bytes(previous_lock) + subprocess.run( + [ + "cargo", + "build", + "--manifest-path", + str(cargo_manifest), + *(["--offline"] if offline else []), + *(["--locked"] if previous_lock is not None else []), + ], + env={**os.environ, "CARGO_TARGET_DIR": str(output / "cargo-target")}, + check=True, + ) + archive = dist / f"{project.name}-{project.version}-cargo.tar.gz" + with tarfile.open(archive, "w:gz") as tar: + tar.add(bundle, arcname=".") + artifacts["cargo_manifest"] = str(cargo_manifest) + artifacts["cargo_archive"] = str(archive) + (output / "artifacts.json").write_text(json.dumps(artifacts, indent=2, sort_keys=True) + "\n") + return artifacts diff --git a/packages/dimos-message-project/src/dimos_message_project/project.py b/packages/dimos-message-project/src/dimos_message_project/project.py new file mode 100644 index 00000000000..d7ea0df9c67 --- /dev/null +++ b/packages/dimos-message-project/src/dimos_message_project/project.py @@ -0,0 +1,228 @@ +# Copyright 2026 Dimensional Inc. +# +# 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. + +"""Project configuration and deterministic generation shared by every build frontend.""" + +from __future__ import annotations + +from dataclasses import dataclass +from hashlib import sha256 +from importlib.util import find_spec +from importlib.metadata import version +import json +from pathlib import Path +import re +import shutil +import sys +from typing import Any + +if sys.version_info >= (3, 11): + import tomllib +else: + import tomli as tomllib + +from dimos_cdrgen.definitions import Definitions, Message +from dimos_cdrgen.generate import generate +from dimos_cdrgen.ownership import ABI, Dependency + +BUILD_VERSION = "0.1.0" +LANGUAGES = frozenset(("python", "cpp", "rust")) + + +@dataclass(frozen=True) +class Project: + root: Path + name: str + version: str + module: str + source: Path + languages: tuple[str, ...] + dependency_specs: dict[str, dict[str, str]] + internal: bool = False + + @classmethod + def load(cls, root: Path) -> Project: + root = root.resolve() + data = tomllib.loads((root / "pyproject.toml").read_text()) + project = data.get("project", {}) + config = data.get("tool", {}).get("dimos", {}).get("messages", {}) + name, version = project.get("name"), project.get("version") + if not isinstance(name, str) or not re.fullmatch(r"[a-z][a-z0-9_-]*", name): + raise ValueError("[project].name must be a lowercase package name") + if not isinstance(version, str) or not re.fullmatch(r"[0-9]+\.[0-9]+\.[0-9]+", version): + raise ValueError("[project].version must be an explicit major.minor.patch version") + allowed = {"source-dir", "python-module", "languages", "dependencies", "internal"} + unknown = config.keys() - allowed + if unknown: + raise ValueError(f"Unknown message configuration: {sorted(unknown)}") + module = config.get("python-module", name.replace("-", "_")) + if not isinstance(module, str) or not re.fullmatch(r"[a-z][a-z0-9_]*", module): + raise ValueError("Invalid python-module") + if module != name.replace("-", "_"): + raise ValueError("python-module must match the normalized project name") + source = (root / config.get("source-dir", "interfaces")).resolve() + if not source.is_relative_to(root): + raise ValueError("Message source-dir must be inside the project") + languages = config.get("languages", ["python"]) + if ( + not isinstance(languages, list) + or not languages + or any(value not in LANGUAGES for value in languages) + ): + raise ValueError("languages must select python, cpp and/or rust") + internal = config.get("internal", False) + if not isinstance(internal, bool): + raise ValueError("internal must be a boolean") + specs = config.get( + "dependencies", {} if internal else {"dimos_generated": {"version": BUILD_VERSION}} + ) + if not isinstance(specs, dict): + raise ValueError("dependencies must map Python modules to exact versions") + for dep_module, spec in specs.items(): + if not re.fullmatch(r"[a-z][a-z0-9_]*", dep_module) or not isinstance(spec, dict): + raise ValueError("Invalid message dependency") + if spec.keys() - {"version", "path"} or not re.fullmatch( + r"[0-9]+\.[0-9]+\.[0-9]+", str(spec.get("version", "")) + ): + raise ValueError(f"Dependency {dep_module} requires an exact version") + if "path" in spec and not isinstance(spec["path"], str): + raise ValueError(f"Dependency path must be a string: {dep_module}") + return cls( + root, name, version, module, source, tuple(dict.fromkeys(languages)), specs, internal + ) + + @property + def output(self) -> Path: + return self.root / "build" / "dimos" + + def requirements(self) -> list[str]: + return [ + f"{module.replace('_', '-')}=={spec['version']}" + for module, spec in sorted(self.dependency_specs.items()) + if "path" not in spec + ] + + def dependencies(self) -> tuple[Dependency, ...]: + result: dict[str, Dependency] = {} + pending = dict(self.dependency_specs) + while pending: + module = sorted(pending)[0] + spec = pending.pop(module) + if module in result: + if result[module].version != spec["version"]: + raise ValueError(f"Conflicting package versions for {module}") + continue + if "path" in spec: + root = (self.root / spec["path"]).resolve() + else: + found = find_spec(module + "_schemas") + if found is None or found.origin is None: + raise ValueError( + f"Install message dependency {module.replace('_', '-')}=={spec['version']} before building (or supply it to pip's build environment)" + ) + root = Path(found.origin).parent / "package" + dep = Dependency.load(root) + if dep.module != module or dep.version != spec["version"]: + raise ValueError( + f"Dependency identity/version mismatch: {module}=={spec['version']}" + ) + if module == self.module: + raise ValueError("A message package cannot depend on itself") + result[module] = dep + metadata = json.loads((root / "message-package.json").read_text()) + for child, version in sorted(metadata.get("dependencies", {}).items()): + expected = {"version": version} + existing = pending.get(child, self.dependency_specs.get(child, expected)) + if existing["version"] != version: + raise ValueError(f"Conflicting package versions for {child}") + pending[child] = existing + return tuple(result[module] for module in sorted(result)) + + +def prepare(project: Project, languages: tuple[str, ...] | None = None) -> Path: + """Generate a complete owned package atomically; never invoke compilers or networks.""" + selected = languages or project.languages + dependencies = project.dependencies() + paths = sorted(project.source.rglob("*.msg")) if project.source.is_dir() else [] + if not paths and not project.internal: + raise ValueError(f"No messages found under {project.source}; expected package/msg/Type.msg") + names = [Message.from_file(path).name for path in paths] + roots = [project.source] if paths else [] + definitions = Definitions(roots + [dep.root / "schemas" for dep in dependencies]) + resolved = definitions.resolve(names if not project.internal else None) + imported = {name for dep in dependencies for name in dep.owned} + unexpected = {message.name for message in resolved} - set(names) - imported + if unexpected and not project.internal: + raise ValueError(f"Missing dependency owners: {sorted(unexpected)}") + if set(names) & imported: + raise ValueError( + f"Local definitions duplicate dependency ownership: {sorted(set(names) & imported)}" + ) + toolkit_hash = sha256(Path(__file__).read_bytes()) + toolkit_hash.update(version("dimos-cdrgen").encode()) + inputs: dict[str, Any] = { + "abi": ABI, + "languages": selected, + "toolkit": toolkit_hash.hexdigest(), + "module": project.module, + "version": project.version, + "names": names, + "internal": project.internal, + "schemas": {message.name: definitions.schema(message.name) for message in resolved}, + "dependencies": [ + { + "module": dep.module, + "version": dep.version, + "schemas": dep.schemas, + "root": str(dep.root), + } + for dep in dependencies + ], + } + digest = sha256(json.dumps(inputs, sort_keys=True).encode()).hexdigest() + output = project.output + state = output / "generation.json" + if state.is_file(): + previous = json.loads(state.read_text()) + if previous.get("digest") == digest and all( + (output / path).is_file() + and sha256((output / path).read_bytes()).hexdigest() == expected + for path, expected in previous.get("files", {}).items() + ): + return output + staging = output.with_name("dimos-generating") + if staging.exists(): + shutil.rmtree(staging) + generate( + roots, + staging, + names if not project.internal else None, + project.module, + version=project.version, + dependencies=dependencies, + shared=True, + languages=selected, + ) + files = { + path.relative_to(staging).as_posix(): sha256(path.read_bytes()).hexdigest() + for path in sorted(staging.rglob("*")) + if path.is_file() + } + (staging / "generation.json").write_text( + json.dumps({"digest": digest, "files": files}, indent=2, sort_keys=True) + "\n" + ) + if output.exists(): + shutil.rmtree(output) + staging.rename(output) + return output diff --git a/pyproject.toml b/pyproject.toml index 86c60a00ef1..7bafc476b3a 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -100,6 +100,7 @@ classifiers = [ ] dependencies = [ + "dimos-message-project==0.1.0", "dimos-generated==0.1.0", "dimos-cdrgen==0.1.0", "matplotlib>=3.7.1", # Rerun initializes point-cloud colormaps for all streams. @@ -577,6 +578,7 @@ override-dependencies = [ ] [tool.uv.sources] +dimos-message-project = { path = "packages/dimos-message-project", editable = true } dimos-generated = { path = "packages/dimos-generated", editable = true } # CUDA builds are not published for macOS or non-x86_64 Linux. Those platforms # fall back to PyPI. diff --git a/uv.lock b/uv.lock index 3d9e8085c79..e6d845269f7 100644 --- a/uv.lock +++ b/uv.lock @@ -1847,6 +1847,7 @@ dependencies = [ { name = "dimos-cdrgen" }, { name = "dimos-generated" }, { name = "dimos-lcm" }, + { name = "dimos-message-project" }, { name = "dimos-viewer" }, { name = "eclipse-zenoh" }, { name = "filelock" }, @@ -2553,6 +2554,7 @@ requires-dist = [ { name = "dimos-cdrgen", specifier = "==0.1.0" }, { name = "dimos-generated", editable = "packages/dimos-generated" }, { name = "dimos-lcm", specifier = ">=0.1.4" }, + { name = "dimos-message-project", editable = "packages/dimos-message-project" }, { name = "dimos-viewer", specifier = "==0.32.0a2" }, { name = "dimos-viewer", marker = "extra == 'visualization'", specifier = "==0.32.0a2" }, { name = "drake", marker = "platform_machine != 'aarch64' and sys_platform == 'darwin' and extra == 'planning'", specifier = "==1.45.0" }, @@ -2950,6 +2952,17 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/d0/d0/f93e2a2d9062ad0b3981b80db12b34494d231917243ab213265e926b5fa9/dimos_lcm-0.1.4-py3-none-any.whl", hash = "sha256:65efc67a5055b8d53a885bb46a7f49cc6bd07929cbd18403784efe65e186d3a2", size = 593548, upload-time = "2026-09-22T20:19:45.404Z" }, ] +[[package]] +name = "dimos-message-project" +version = "0.1.0" +source = { editable = "packages/dimos-message-project" } +dependencies = [ + { name = "dimos-cdrgen" }, +] + +[package.metadata] +requires-dist = [{ name = "dimos-cdrgen", specifier = "==0.1.0" }] + [[package]] name = "dimos-viewer" version = "0.32.0a2"