{"id":19195235,"url":"https://github.com/quartiq/crosstrait","last_synced_at":"2025-07-22T13:05:03.152Z","repository":{"id":246784052,"uuid":"823017594","full_name":"quartiq/crosstrait","owner":"quartiq","description":"Cast from `dyn Any` to other trait objects, with no_std, no alloc support","archived":false,"fork":false,"pushed_at":"2025-07-10T15:28:39.000Z","size":16,"stargazers_count":3,"open_issues_count":0,"forks_count":1,"subscribers_count":2,"default_branch":"main","last_synced_at":"2025-07-18T11:47:45.753Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/quartiq.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2024-07-02T09:14:10.000Z","updated_at":"2025-07-10T15:28:38.000Z","dependencies_parsed_at":null,"dependency_job_id":"2fc59e18-8eab-468a-9188-b84d607bf4df","html_url":"https://github.com/quartiq/crosstrait","commit_stats":null,"previous_names":["quartiq/crosstrait"],"tags_count":1,"template":false,"template_full_name":null,"purl":"pkg:github/quartiq/crosstrait","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/quartiq%2Fcrosstrait","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/quartiq%2Fcrosstrait/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/quartiq%2Fcrosstrait/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/quartiq%2Fcrosstrait/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/quartiq","download_url":"https://codeload.github.com/quartiq/crosstrait/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/quartiq%2Fcrosstrait/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":266499026,"owners_count":23938774,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-07-22T02:00:09.085Z","response_time":66,"last_error":null,"robots_txt_status":null,"robots_txt_updated_at":null,"robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-11-09T12:09:12.927Z","updated_at":"2025-07-22T13:05:03.129Z","avatar_url":"https://github.com/quartiq.png","language":"Rust","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Cast from `dyn Any` to other trait objects\n\n* `no_std` no alloc support\n* No proc macros\n* No unsafe code\n\n## Usage\n\n```toml\n[dependencies]\ncrosstrait = \"0.1\"\n```\n\nThen use the `register!{ Type =\u003e Trait }` declarative macro and the [`Cast`] traits.\n\nFor embedded, the linker needs to be informed of the type registry.\n\n## Example\n\n```rust\nuse core::any::Any;\nuse crosstrait::{Cast, Castable, CastableRef, entry, register, REGISTRY, Registry};\n\n// Some example traits to play with\nuse core::{fmt::{Debug, Formatter, Write}, ops::{AddAssign, SubAssign}};\n\n// Add types and trait implementations to the default registry\n// Implementation status is verified at compile time\nregister! { i32 =\u003e dyn Debug }\n\n// Registering foreign types and traits works fine\n// Serialization/deserialization of `dyn Any` is a major use case\n// register! { i32 =\u003e dyn erased_serde::Serialize }\n\n// If a type is not Send + Sync, it can't cast as Arc.\n// `no_arc` accounts for that\nregister! { Formatter =\u003e dyn Write, no_arc }\n\n// Check for trait impl registration on concrete type\nassert!(i32::castable::\u003cdyn Debug\u003e());\n\n// Check for trait impl registration on Any\nlet any: \u0026dyn Any = \u002642i32;\nassert!(any.castable::\u003cdyn Debug\u003e());\n\n// SubAssign\u003ci32\u003e is impl'd for i32 but not registered\nassert!(!any.castable::\u003cdyn SubAssign\u003ci32\u003e\u003e());\n\n// Cast ref\nlet a: \u0026dyn Debug = any.cast().unwrap();\nprintln!(\"42 = {a:?}\");\n\n// Cast mut\nlet mut value = 5i32;\nlet any: \u0026mut dyn Any = \u0026mut value;\nlet v: \u0026mut dyn AddAssign\u003ci32\u003e = any.cast().unwrap();\n*v += 3;\nassert_eq!(value, 5 + 3);\n\n// Cast Box\nlet any: Box\u003cdyn Any\u003e = Box::new(0i32);\nlet _: Box\u003cdyn Debug\u003e = any.cast().unwrap();\n\n// Cast Rc\nuse std::rc::Rc;\nlet any: Rc\u003cdyn Any\u003e = Rc::new(0i32);\nlet _: Rc\u003cdyn Debug\u003e = any.cast().unwrap();\n\n// Cast Arc\nuse std::sync::Arc;\nlet any: Arc\u003cdyn Any + Sync + Send\u003e = Arc::new(0i32);\nlet _: Arc\u003cdyn Debug\u003e = any.cast().unwrap();\n\n// Explicit registry usage\nlet any: \u0026dyn Any = \u00260i32;\nlet _: \u0026dyn Debug = REGISTRY.cast_ref(any).unwrap();\n\n// Custom non-static registry\nlet myreg = Registry::new(\u0026[entry!(i32 =\u003e dyn Debug)]);\nlet _: \u0026dyn Debug = myreg.cast_ref(any).unwrap();\n\n// Autotraits and type/const generics are distinct\nlet a: Option\u003c\u0026(dyn Debug + Sync)\u003e = any.cast();\nassert!(a.is_none());\n\n// Registration in the default registry can happen anywhere\n// in any order in any downstream crate\nregister! { i32 =\u003e dyn AddAssign\u003ci32\u003e }\n```\n\n## Related crates\n\n* [`intertrait`](https://crates.io/crates/intertrait): source of ideas for `crosstrait`, similar goals, similar features, `std`, proc macros\n* [`miniconf`](https://crates.io/crates/miniconf): provides several ways to get `dyn Any` from nodes in\n  heterogeneous nested data structures, `no_std`, no alloc\n* [`erased_serde`](https://crates.io/crates/erased-serde): `Serialize`/`Serializer`/`Deserializer` trait objects\n* [`downcast`](https://crates.io/crates/downcast)/[`downcast-rs`](https://crates.io/crates/downcast-rs): support `dyn Trait -\u003e Type`\n* [`linkme`](https://crates.io/crates/linkme): linker magic used here to build distributed static type registry\n\n## Limitations\n\n### Registry size on `no_std`\n\nCurrently the size of the global registry on `no_std` is fixed and arbitrarily set to 128 entries.\n\n### Auto traits\n\nSince adding any combination of auto traits (in particular `Send`, `Sync`, `Unpin`) to a trait results in a distinct trait,\nall relevant combinations of traits plus auto traits needs to be registered explicitly.\n\n### Global registry\n\nA custom non-static [`Registry`] can be built and used explicitly but the `Cast` traits will not use it.\n\n### `used_linker`\n\nThe unstable `used_with_arg` feature may be required to keep the linker from optimizing away the items in the registry.\nEnable it using the `used_linker` crate feature and use a nightly toolchain.\n\n### Registry keys\n\nThe registry keys are `size_of::\u003c[TypeId; 2]\u003e() = 32` bytes large.\nHashing and key storage/comparison is not tuned for performance.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fquartiq%2Fcrosstrait","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fquartiq%2Fcrosstrait","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fquartiq%2Fcrosstrait/lists"}