{"id":15698521,"url":"https://github.com/sof3/xylem","last_synced_at":"2026-03-14T16:01:37.328Z","repository":{"id":57672680,"uuid":"425476719","full_name":"SOF3/xylem","owner":"SOF3","description":"A Rust framework for stateful type conversion.","archived":false,"fork":false,"pushed_at":"2023-03-21T14:38:58.000Z","size":116,"stargazers_count":6,"open_issues_count":2,"forks_count":0,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-04-20T09:39:13.418Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"https://docs.rs/xylem/","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/SOF3.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","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}},"created_at":"2021-11-07T10:49:08.000Z","updated_at":"2023-12-07T21:12:40.000Z","dependencies_parsed_at":"2024-10-24T03:51:50.427Z","dependency_job_id":"1888dfac-21f3-44b2-9d44-71fb33c8af27","html_url":"https://github.com/SOF3/xylem","commit_stats":{"total_commits":34,"total_committers":2,"mean_commits":17.0,"dds":0.02941176470588236,"last_synced_commit":"497f50037d643e2b16ef701ceb6f665ad9a3e146"},"previous_names":[],"tags_count":8,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SOF3%2Fxylem","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SOF3%2Fxylem/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SOF3%2Fxylem/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SOF3%2Fxylem/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/SOF3","download_url":"https://codeload.github.com/SOF3/xylem/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":253156872,"owners_count":21863018,"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","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-10-03T19:29:18.002Z","updated_at":"2026-03-14T16:01:37.035Z","avatar_url":"https://github.com/SOF3.png","language":"Rust","funding_links":[],"categories":[],"sub_categories":[],"readme":"# xylem\n[![GitHub actions](https://github.com/SOF3/xylem/workflows/CI/badge.svg)](https://github.com/SOF3/xylem/actions?query=workflow%3ACI)\n[![crates.io](https://img.shields.io/crates/v/xylem.svg)](https://crates.io/crates/xylem)\n[![crates.io](https://img.shields.io/crates/d/xylem.svg)](https://crates.io/crates/xylem)\n[![docs.rs](https://docs.rs/xylem/badge.svg)](https://docs.rs/xylem)\n[![GitHub](https://img.shields.io/github/last-commit/SOF3/xylem)](https://github.com/SOF3/xylem)\n[![GitHub](https://img.shields.io/github/stars/SOF3/xylem?style=social)](https://github.com/SOF3/xylem)\n\nXylem is a stateful type conversion framework for Rust.\n\n## Concepts\nXylem provides the [`Xylem`] trait,\nwhich is similar to the [`std::convert::TryFrom`] trait,\nbut with the following differences:\n\n### Stateful context\n[`Xylem::convert`] passes a mutable [`Context`],\nenabling stateful operations throughout the conversion process.\nSee [`Context`] documentation for details.\n\n### Fixed concersion source\nUnlike [`std::convert::TryFrom`],\n[`Xylem`] takes the conversion source type\nas an associated type [`Xylem::From`]\ninstead of a generic parameter.\nThis means each type can only be converted\nfrom exactly one other specific type under a given [`Schema`].\n\n### Schemas\n[`Xylem`] accepts a type parameter `S` (\"schema\"),\nwhich acts as a namespace defining the set of conversion rules.\nThis allows different downstream crates\nto define their own conversion rules\nwithout conflicting with each other.\nFor example, if crate `foo` wants to convert `bool` from `String`\nand crate `bar` wants to convert `bool` from `i32`,\nthey can separately define schema types `foo::Xylem` and `bar::Xylem`,\nthen separately implement\n\n```rust\nimpl Xylem\u003cfoo::Schema\u003e for bool {\n    type From = String;\n    // fn convert() omitted\n}\nimpl Xylem\u003cbar::Schema\u003e for bool {\n    type From = i32;\n    // fn convert() omitted\n}\n```\n\nFurthermore, since `foo::Schema` and `bar::Schema`\nare declared in their own crates,\n`Xylem\u003cS\u003e` is not considered a foreign trait,\nso implementing custom conversion rules for [`std`] types\nwill not result in\n[error E0220](https://doc.rust-lang.org/error-index.html#E0220) or\n[error E0119](https://doc.rust-lang.org/error-index.html#E0119).\n\nTo use the default conversion rules defined by xylem,\nmake the schema implement the [`SchemaExt`] trait.\nThere is a convenience macro [`declare_schema`] for this:\n\n```rust\nxylem::declare_schema!(Schema: xylem::SchemaExt);\n\n// we defined a schema type called `Schema`.\n```\n\nIt is recommended to use `Schema` as the schema name\nand declare it at the crate level,\nbecause the [`Xylem`][xylem_codegen::Xylem] macro\nuses `crate::Schema` as the default schema type.\n\n## The `Xylem` macro\nXylem provides a [`Xylem`][xylem_codegen::Xylem] macro,\nwhich derives the corresponding [`Xylem::From`] type\nfrom a struct or enum\nby replacing each type with the corresponding [`Xylem::From`] type,\nas well as a [`Xylem`] implementation.\nSee the [`Xylem`][xylem_codegen::Xylem] documentation for details.\n\nNote that the order of fields matters\nbecause xylem type conversion is stateful,\ni.e. previous conversions may affect subsequent ones.\n\n\n## The `id` feature\nWith the `id` feature enabled,\nxylem provides the [`Id`] type,\nwhich is the motivational use case for xylem:\nDeserialize a config file that references other fields by string ID,\nreplace each declaring ID with an integer storing its occurrence order,\nand replace each referencing ID with the occurrence order of the declaring ID.\n\nThe [`Id`] type takes two generic parameters, `S` and `X`.\nThe type `S` is just the schema type,\nwhile the type `X` is the subject of identification.\n`X` must also implement the [`Identifiable`] trait,\nwhich has an associated type [`Identifiable::Scope`]\nused to provide a namespace for the ID.\nThe declaring [`Id`] field must be declared under `X`,\nand `X` must occur as a (transitive) child of the scope.\nFurther references to the ID of `X`\nmust occur also as transitive children of the scope,\nbecause the scope is dropped when it completes parsing.\n\nDeclaring IDs are marked with the argument `new = true`.\nIf the ID is to be cross-referenced after the scope drops,\nalso mark `track = true`.\nReferencing IDs do not need to be marked,\nbut if they serve to import a scope,\nthey should be marked as `import = true`.\n\nSee [tests/id.rs](https://docs.rs/crate/xylem/*/source/tests/id.rs) and\n[tests/cross\\_id.rs](https://docs.rs/crate/xylem/*/source/tests/cross_id.rs) for example usage.\n\nNote that it is not a design goal for xylem to support lookahead IDs.\nDue to the stateful nature of xylem,\nIDs are only indexed when the declaration has been scanned.\nThere is currently no plan to implement multiple passes\nto pre-index IDs.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsof3%2Fxylem","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsof3%2Fxylem","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsof3%2Fxylem/lists"}