{"id":20548072,"url":"https://github.com/lusingander/umbra","last_synced_at":"2025-09-25T18:31:06.825Z","repository":{"id":258851023,"uuid":"870939628","full_name":"lusingander/umbra","owner":"lusingander","description":"A macro to generate optional structs 🌒","archived":false,"fork":false,"pushed_at":"2024-12-07T01:24:37.000Z","size":15,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-01-02T17:22:06.152Z","etag":null,"topics":["macros","rust"],"latest_commit_sha":null,"homepage":"","language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/lusingander.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":"2024-10-11T00:28:18.000Z","updated_at":"2024-12-07T01:24:40.000Z","dependencies_parsed_at":"2024-12-02T09:30:48.500Z","dependency_job_id":"cb99e45e-e524-4bba-9c6a-072bf3ed30d9","html_url":"https://github.com/lusingander/umbra","commit_stats":null,"previous_names":["lusingander/umbra"],"tags_count":3,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lusingander%2Fumbra","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lusingander%2Fumbra/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lusingander%2Fumbra/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lusingander%2Fumbra/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/lusingander","download_url":"https://codeload.github.com/lusingander/umbra/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":234230456,"owners_count":18799863,"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":["macros","rust"],"created_at":"2024-11-16T02:11:55.135Z","updated_at":"2025-09-25T18:31:06.820Z","avatar_url":"https://github.com/lusingander.png","language":"Rust","funding_links":[],"categories":[],"sub_categories":[],"readme":"# umbra\n\n[![Crate Status](https://img.shields.io/crates/v/umbra.svg)](https://crates.io/crates/umbra)\n\nA macro to generate optional structs\n\n## About\n\nUmbra provides a macro that generates the struct where each field in the struct is of type Option.\n\n### Why?\n\nFor example, if you use serde to load a config file, you may find it a bit tedious to deal with optional settings. Umbra will generate the struct with optional fields and conversions back to the original struct, which may make writing such programs a little easier.\n\nHere is an example of usage:\n\n```rust\n// The target struct is marked as `umbra::optional`.\n// The generated struct is marked as `serde::Deserialize` as the derive.\n#[umbra::optional(derives = [serde::Deserialize])]\n#[derive(Debug)]\nstruct Config {\n  log_level: String,\n  cache: bool,\n  timeout_seconds: usize,\n}\n\nimpl Default for Config {\n  fn default() -\u003e Self {\n    Config {\n      log_level: \"warn\".into(),\n      cache: true,\n      timeout_seconds: 30,\n    }\n  }\n}\n\nfn load_config(config_str: \u0026str) -\u003e Config {\n  // A struct definition with optional fields and `Into` the original struct are provided.\n  let config: OptionalConfig = toml::from_str(config_str).unwrap();\n  config.into()\n}\n\nfn main() {\n  // Any fields you specify will be set to their values,\n  // others will be set to the default values defined in the `Default` trait.\n  let config_str = r#\"\n    timeout_seconds = 10\n  \"#;\n  let config = load_config(config_str);\n\n  println!(\"{:?}\", config);\n  // =\u003e Config { log_level: \"warn\", cache: true, timeout_seconds: 10 }\n}\n\n```\n\n## Usage\n\n### Basic\n\nAdd the `#[optional]` and `#[nested]` attributes as follows:\n\n```rs\nuse umbra::optional;\n\n#[optional]\n#[derive(Default)]\nstruct Foo {\n  id: u32,\n  name: String,\n  #[nested]\n  bar: Bar,\n}\n\n#[optional]\n#[derive(Default)]\nstruct Bar {\n  name: String,\n  value: Option\u003ci32\u003e,\n}\n```\n\nThe macro generates following structs:\n\n```rs\n#[derive(Default)]\nstruct Foo {\n  id: u32,\n  name: String,\n  bar: Bar,\n}\n\n#[derive(Default)]\nstruct Bar {\n  name: String,\n  value: Option\u003ci32\u003e,\n}\n\nstruct OptionalFoo {\n  id: Option\u003cu32\u003e,\n  name: Option\u003cString\u003e,\n  bar: Option\u003cOptionalBar\u003e,\n}\n\nimpl From\u003cOptionalFoo\u003e for Foo {\n  fn from(optional: OptionalFoo) -\u003e Self {\n      let mut base = Self::default(); // create base values by default\n      if let Some(value) = optional.id {\n          base.id = value; // simple field\n      }\n      if let Some(value) = optional.bar {\n          base.bar = value.into(); // nested field\n      }\n      // ...\n      base\n  }\n}\n\nstruct OptionalBar {\n  name: Option\u003cString\u003e,\n  value: Option\u003ci32\u003e,\n}\n\nimpl From\u003cOptionalBar\u003e for Bar {\n  fn from(optional: OptionalBar) -\u003e Self {\n      let mut base = Self::default();\n      // ...\n      base\n  }\n}\n```\n\n### Derives\n\nBy using the `derives` attribute, the derive attribute can be added to the generated struct:\n\n```rs\nuse umbra::optional;\n\n#[optional(derives = [Debug, std::clone::Clone])]\n#[derive(Default)]\nstruct Foo {\n  id: u32,\n  name: String,\n}\n```\n\nThe macro generates following structs:\n\n```rs\n#[derive(Default)]\nstruct Foo {\n  id: u32,\n  name: String,\n}\n\n#[derive(Debug, std::clone::Clone)] // The derive attribute is added\nstruct OptionalFoo {\n  id: Option\u003cu32\u003e,\n  name: Option\u003cString\u003e,\n}\n\nimpl From\u003cOptionalFoo\u003e for Foo {\n  fn from(optional: OptionalFoo) -\u003e Self {\n      let mut base = Self::default();\n      // ...\n      base\n  }\n}\n```\n\n### Prefix / Suffix\n\nBy using the `prefix` and `suffix` attributes, the prefix and suffix of the generated struct are changed:\n\n```rs\nuse umbra::optional;\n\n#[optional(prefix = \"Pre\", suffix = \"Suf\")]\n#[derive(Default)]\nstruct Foo {\n  id: u32,\n  name: String,\n}\n```\n\nThe macro generates following structs:\n\n```rs\n#[derive(Default)]\nstruct Foo {\n  id: u32,\n  name: String,\n}\n\nstruct PreFooSuf { // \u003cPrefix\u003e\u003cBase name\u003e\u003cSuffix\u003e format\n  id: Option\u003cu32\u003e,\n  name: Option\u003cString\u003e,\n}\n\nimpl From\u003cPreFooSuf\u003e for Foo {\n  fn from(optional: PreFooSuf) -\u003e Self {\n      let mut base = Self::default();\n      // ...\n      base\n  }\n}\n```\n\n### Visibility\n\nBy using the `visibility` attribute, the visibility can be added to the generated struct:\n\n```rs\nuse umbra::optional;\n\n#[optional(visibility = pub)]\n#[derive(Default)]\nstruct Foo {\n  id: u32,\n  name: String,\n}\n```\n\nThe macro generates following structs:\n\n```rs\n#[derive(Default)]\nstruct Foo {\n  id: u32,\n  name: String,\n}\n\npub struct OptionalFoo { // public\n  id: Option\u003cu32\u003e,\n  name: Option\u003cString\u003e,\n}\n\nimpl From\u003cOptionalFoo\u003e for Foo {\n  fn from(optional: OptionalFoo) -\u003e Self {\n      let mut base = Self::default();\n      // ...\n      base\n  }\n}\n```\n\n## License\n\nMIT\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flusingander%2Fumbra","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Flusingander%2Fumbra","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flusingander%2Fumbra/lists"}