{"id":21145011,"url":"https://github.com/heliozoa/elm_rs","last_synced_at":"2025-10-05T16:19:17.648Z","repository":{"id":43770610,"uuid":"399012791","full_name":"Heliozoa/elm_rs","owner":"Heliozoa","description":"Generate Elm type definitions and JSON encoders/decoders from Rust types.","archived":false,"fork":false,"pushed_at":"2025-03-08T11:28:14.000Z","size":412,"stargazers_count":30,"open_issues_count":1,"forks_count":4,"subscribers_count":2,"default_branch":"main","last_synced_at":"2025-04-07T13:05:55.825Z","etag":null,"topics":["elm","full-stack-web-development","rust"],"latest_commit_sha":null,"homepage":"https://crates.io/crates/elm_rs","language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mpl-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Heliozoa.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","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-08-23T07:31:41.000Z","updated_at":"2025-03-08T11:28:18.000Z","dependencies_parsed_at":"2025-03-08T12:21:06.383Z","dependency_job_id":"3e07c471-05d3-4621-b40f-d4f4fd822df2","html_url":"https://github.com/Heliozoa/elm_rs","commit_stats":null,"previous_names":[],"tags_count":10,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Heliozoa%2Felm_rs","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Heliozoa%2Felm_rs/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Heliozoa%2Felm_rs/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Heliozoa%2Felm_rs/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Heliozoa","download_url":"https://codeload.github.com/Heliozoa/elm_rs/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247657276,"owners_count":20974344,"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":["elm","full-stack-web-development","rust"],"created_at":"2024-11-20T08:35:24.512Z","updated_at":"2025-10-05T16:19:17.550Z","avatar_url":"https://github.com/Heliozoa.png","language":"Rust","funding_links":[],"categories":[],"sub_categories":[],"readme":"# elm_rs\n\n[![Crates.io](https://img.shields.io/crates/v/elm_rs)](https://crates.io/crates/elm_rs)\n[![docs.rs](https://img.shields.io/badge/docs.rs-elm__rs-success)](https://docs.rs/elm_rs)\n[![Crates.io](https://img.shields.io/crates/l/elm_rs)](https://choosealicense.com/licenses/mpl-2.0/)\n[![GitHub](https://img.shields.io/badge/GitHub-Heliozoa-24292f)](https://github.com/Heliozoa/elm_rs)\n\nAutomatically generate type definitions and functions for your Elm frontend from your Rust backend types, making it easy to keep the two in sync. Currently supports generating\n- Elm types with the `Elm` trait and derive macro\n- JSON encoders with the `ElmEncode` trait and derive macro, compatible with `serde_json`\n- JSON decoders with the `ElmDecode` trait and derive macro, compatible with `serde_json`\n- URL query encoders with the `ElmQuery` and `ElmQueryField` traits and derive macros\n\n## Usage\nFor example, the following code\n```rust\nuse elm_rs::{Elm, ElmEncode, ElmDecode, ElmQuery, ElmQueryField};\n\n#[derive(Elm, ElmEncode, ElmDecode)]\nenum Filetype {\n    Jpeg,\n    Png,\n}\n\n#[derive(Elm, ElmEncode, ElmDecode)]\nstruct Drawing {\n    title: String,\n    authors: Vec\u003cString\u003e,\n    filename: String,\n    filetype: Filetype,\n}\n\n#[derive(Elm, ElmQuery)]\nstruct Query {\n    page: usize,\n    thumbnail_size: Size,\n}\n\n#[derive(Elm, ElmQueryField)]\nenum Size {\n    Small,\n    Large,\n}\n\nfn main() {\n    // the target would typically be a file\n    let mut target = vec![];\n    // elm_rs provides a macro for conveniently creating an Elm module with everything needed\n    elm_rs::export!(\"Bindings\", \u0026mut target, {\n        // generates types and encoders for types implementing ElmEncoder\n        encoders: [Filetype, Drawing],\n        // generates types and decoders for types implementing ElmDecoder\n        decoders: [Filetype, Drawing],\n        // generates types and functions for forming queries for types implementing ElmQuery\n        queries: [Query],\n        // generates types and functions for forming queries for types implementing ElmQueryField\n        query_fields: [Size],\n    }).unwrap();\n    let output = String::from_utf8(target).unwrap();\n    println!(\"{}\", output);\n}\n```\nprints out\n```elm\n\n-- generated by elm_rs\n\n\nmodule Bindings exposing (..)\n\nimport Dict exposing (Dict)\nimport Http\nimport Json.Decode\nimport Json.Encode\nimport Url.Builder\n\n\nresultEncoder : (e -\u003e Json.Encode.Value) -\u003e (t -\u003e Json.Encode.Value) -\u003e (Result e t -\u003e Json.Encode.Value)\nresultEncoder errEncoder okEncoder enum =\n    case enum of\n        Ok inner -\u003e\n            Json.Encode.object [ ( \"Ok\", okEncoder inner ) ]\n        Err inner -\u003e\n            Json.Encode.object [ ( \"Err\", errEncoder inner ) ]\n\n\nresultDecoder : Json.Decode.Decoder e -\u003e Json.Decode.Decoder t -\u003e Json.Decode.Decoder (Result e t)\nresultDecoder errDecoder okDecoder =\n    Json.Decode.oneOf\n        [ Json.Decode.map Ok (Json.Decode.field \"Ok\" okDecoder)\n        , Json.Decode.map Err (Json.Decode.field \"Err\" errDecoder)\n        ]\n\n\ntype Filetype\n    = Jpeg\n    | Png\n\n\nfiletypeEncoder : Filetype -\u003e Json.Encode.Value\nfiletypeEncoder enum =\n    case enum of\n        Jpeg -\u003e\n            Json.Encode.string \"Jpeg\"\n        Png -\u003e\n            Json.Encode.string \"Png\"\n\ntype alias Drawing =\n    { title : String\n    , authors : List (String)\n    , filename : String\n    , filetype : Filetype\n    }\n\n\ndrawingEncoder : Drawing -\u003e Json.Encode.Value\ndrawingEncoder struct =\n    Json.Encode.object\n        [ ( \"title\", (Json.Encode.string) struct.title )\n        , ( \"authors\", (Json.Encode.list (Json.Encode.string)) struct.authors )\n        , ( \"filename\", (Json.Encode.string) struct.filename )\n        , ( \"filetype\", (filetypeEncoder) struct.filetype )\n        ]\n\n\nfiletypeDecoder : Json.Decode.Decoder Filetype\nfiletypeDecoder = \n    Json.Decode.oneOf\n        [ Json.Decode.string\n            |\u003e Json.Decode.andThen\n                (\\x -\u003e\n                    case x of\n                        \"Jpeg\" -\u003e\n                            Json.Decode.succeed Jpeg\n                        unexpected -\u003e\n                            Json.Decode.fail \u003c| \"Unexpected variant \" ++ unexpected\n                )\n        , Json.Decode.string\n            |\u003e Json.Decode.andThen\n                (\\x -\u003e\n                    case x of\n                        \"Png\" -\u003e\n                            Json.Decode.succeed Png\n                        unexpected -\u003e\n                            Json.Decode.fail \u003c| \"Unexpected variant \" ++ unexpected\n                )\n        ]\n\ndrawingDecoder : Json.Decode.Decoder Drawing\ndrawingDecoder =\n    Json.Decode.succeed Drawing\n        |\u003e Json.Decode.andThen (\\x -\u003e Json.Decode.map x (Json.Decode.field \"title\" (Json.Decode.string)))\n        |\u003e Json.Decode.andThen (\\x -\u003e Json.Decode.map x (Json.Decode.field \"authors\" (Json.Decode.list (Json.Decode.string))))\n        |\u003e Json.Decode.andThen (\\x -\u003e Json.Decode.map x (Json.Decode.field \"filename\" (Json.Decode.string)))\n        |\u003e Json.Decode.andThen (\\x -\u003e Json.Decode.map x (Json.Decode.field \"filetype\" (filetypeDecoder)))\n\n\ntype alias Query =\n    { page : Int\n    , thumbnailSize : Size\n    }\n\n\nurlEncodeQuery : Query -\u003e List Url.Builder.QueryParameter\nurlEncodeQuery struct =\n    [ Url.Builder.int \"page\" (identity struct.page), Url.Builder.string \"thumbnail_size\" (queryFieldEncoderSize struct.thumbnailSize) ]\n\n\ntype Size\n    = Small\n    | Large\n\n\nqueryFieldEncoderSize : Size -\u003e String\nqueryFieldEncoderSize var =\n    case var of\n        Small -\u003e \"Small\"\n        Large -\u003e \"Large\"\n\n```\n\n## Functionality\n\n### Cargo features\n- `derive`: Activated by default. Enables deriving the `Elm` and `ElmEncode` traits.\n- `serde`: Enables compatibility with many of serde's attributes. (`serde v1`)\n- `chrono`: Trait implementations for chrono types. (`chrono v0.4`)\n- `time`: Trait implementations for time types. (`time v0.3`)\n- `uuid`: Trait implementations for uuid types. (`uuid v1`)\n\n### Serde compatibility\nThe `serde` feature enables compatibility with serde attributes. Currently the following attributes are supported:\n\n#### Container attributes\n- rename_all\n- tag\n- tag \u0026 content\n- untagged\n- transparent\n\n#### Variant attributes\n- rename\n- rename_all\n- skip\n- other\n\n#### Field attributes\n- rename\n- skip\n\n### 0.2.0\n- [x] Generate Elm types with the `Elm` trait and derive macro\n- [x] Generate JSON encoders and decoders with the `ElmEncode` and `ElmDecode` traits and derive macros\n- [x] Basic generic support\n- [x] Compatibility with most serde attributes\n- [x] Support for simple queries\n\n### Planned\n- [ ] Support for forms and complex queries\n- [ ] Compatibility with more serde attributes\n  - [ ] flatten\n  - [ ] alias\n  - [ ] skip_(de)serializing\n- [ ] Optionally include definitions for the dependencies of exported types\n- [ ] Implement support for more `serde::{Deserialize, Serialize}` std types\n  - [ ] IpAddr, Ipv4Addr, Ipv6Addr\n  - [ ] SocketAddr, SocketAddrV4, SocketAddrV6\n  - [ ] PhantomData\n- [ ] Handle recursive types\n- [ ] Attributes for controlling the name of the Elm type etc.\n\n### Known limitations\nGeneric types are not well supported when they are used with more than one set of concrete types. For example, for\n```rust\nstruct Generic\u003cT\u003e(T);\n```\n`Generic::\u003cu32\u003e::elm_definition()` and `Generic::\u003cString\u003e::elm_definition()` will both use the name `Generic` for the Elm definition, causing an error in Elm. Accidentally using different generic types for the generated JSON and the Elm definition can also result in some confusing error messages.\n\nReusing enum variant names is allowed in Rust but not in Elm. Therefore generating definitions for the two enums\n```rust\nenum Enum1 {\n    Variant\n}\nenum Enum2 {\n    Variant\n}\n```\nwill cause an error in Elm due to `Variant` being ambiguous.\n\n## Alternatives\n\n- Generate an OpenAPI spec from Rust with something like https://crates.io/crates/okapi and generate Elm code from the spec with something like https://openapi-generator.tech/.\n\n## License\nLicensed under the Mozilla Public License Version 2.0.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fheliozoa%2Felm_rs","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fheliozoa%2Felm_rs","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fheliozoa%2Felm_rs/lists"}