{"id":18568664,"url":"https://github.com/x-hgg-x/custom-format","last_synced_at":"2025-04-10T05:32:58.684Z","repository":{"id":46905458,"uuid":"515739740","full_name":"x-hgg-x/custom-format","owner":"x-hgg-x","description":"Custom formatting for Rust.","archived":false,"fork":false,"pushed_at":"2024-05-19T07:23:14.000Z","size":80,"stargazers_count":9,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-03-24T16:47:38.696Z","etag":null,"topics":["fmt","macro","no-std","rust"],"latest_commit_sha":null,"homepage":"","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/x-hgg-x.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE-Apache","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":"2022-07-19T20:59:09.000Z","updated_at":"2024-05-19T07:23:17.000Z","dependencies_parsed_at":"2024-11-06T22:34:37.318Z","dependency_job_id":"67e42495-4e38-4a2a-836f-dcb00f342b02","html_url":"https://github.com/x-hgg-x/custom-format","commit_stats":{"total_commits":36,"total_committers":1,"mean_commits":36.0,"dds":0.0,"last_synced_commit":"1507a8e6fc45e965e79bb2a452776ae5d7dc8aa4"},"previous_names":[],"tags_count":11,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/x-hgg-x%2Fcustom-format","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/x-hgg-x%2Fcustom-format/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/x-hgg-x%2Fcustom-format/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/x-hgg-x%2Fcustom-format/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/x-hgg-x","download_url":"https://codeload.github.com/x-hgg-x/custom-format/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248163303,"owners_count":21057906,"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":["fmt","macro","no-std","rust"],"created_at":"2024-11-06T22:29:55.917Z","updated_at":"2025-04-10T05:32:56.933Z","avatar_url":"https://github.com/x-hgg-x.png","language":"Rust","funding_links":[],"categories":[],"sub_categories":[],"readme":"# custom-format\n\n[![version](https://img.shields.io/crates/v/custom-format?color=blue\u0026style=flat-square)](https://crates.io/crates/custom-format)\n![Minimum supported Rust version](https://img.shields.io/badge/rustc-1.56+-important?logo=rust \"Minimum Supported Rust Version\")\n[![Documentation](https://docs.rs/custom-format/badge.svg)](https://docs.rs/custom-format)\n\nThis crate extends the standard formatting syntax with custom format specifiers, by providing custom formatting macros.\n\nIt uses ` :` (a space and a colon) as a separator before the format specifier, which is not a syntax currently accepted and allows supporting standard specifiers in addition to custom specifiers. It also supports [format args capture](https://blog.rust-lang.org/2022/01/13/Rust-1.58.0.html#captured-identifiers-in-format-strings) even on older versions of Rust, since it manually adds the named parameter if missing.\n\nThis library comes in two flavors, corresponding to the following features:\n\n- `compile-time` (*enabled by default*)\n\n    The set of possible custom format specifiers is defined at compilation, so invalid specifiers can be checked at compile-time.\n    This allows the library to have the same performance as when using the standard library formatting traits.\n\n- `runtime` (*enabled by default*)\n\n    The formatting method dynamically checks the format specifier at runtime for each invocation.\n    This is a slower version, but it has additional flexibility.\n\n## Documentation\n\nDocumentation is hosted on [docs.rs](https://docs.rs/custom-format/latest/).\n\n## Example\n\n\u003cdetails\u003e\n\u003csummary\u003eCode\u003c/summary\u003e\n\n```rust\nuse custom_format as cfmt;\n\nuse core::fmt;\n\npub struct DateTime {\n    year: i32,\n    month: u8,\n    month_day: u8,\n    hour: u8,\n    minute: u8,\n    second: u8,\n    nanoseconds: u32,\n}\n\nmacro_rules! impl_custom_format_for_datetime {\n    (match spec { $($spec:literal =\u003e $func:expr $(,)?)* }) =\u003e {\n        use cfmt::compile_time::{spec, CustomFormat};\n        $(\n            impl CustomFormat\u003c{ spec($spec) }\u003e for DateTime {\n                fn fmt(\u0026self, f: \u0026mut fmt::Formatter) -\u003e fmt::Result {\n                    ($func as fn(\u0026Self, \u0026mut fmt::Formatter) -\u003e fmt::Result)(self, f)\n                }\n            }\n        )*\n    };\n}\n\n// Static format specifiers, checked at compile-time\nimpl_custom_format_for_datetime!(match spec {\n    // Year with pad for at least 4 digits\n    \"%Y\" =\u003e |this, f| write!(f, \"{:04}\", this.year),\n    // Year % 100 (00..99)\n    \"%y\" =\u003e |this, f| write!(f, \"{:02}\", (this.year % 100).abs()),\n    // Month of the year, zero-padded (01..12)\n    \"%m\" =\u003e |this, f| write!(f, \"{:02}\", this.month),\n    // Day of the month, zero-padded (01..31)\n    \"%d\" =\u003e |this, f| write!(f, \"{:02}\", this.month_day),\n    // Hour of the day, 24-hour clock, zero-padded (00..23)\n    \"%H\" =\u003e |this, f| write!(f, \"{:02}\", this.hour),\n    // Minute of the hour (00..59)\n    \"%M\" =\u003e |this, f| write!(f, \"{:02}\", this.minute),\n    // Second of the minute (00..60)\n    \"%S\" =\u003e |this, f| write!(f, \"{:02}\", this.second),\n    // Date (%m/%d/%y)\n    \"%D\" =\u003e {\n        |this, f| {\n            let month = cfmt::custom_formatter!(\"%m\", this);\n            let day = cfmt::custom_formatter!(\"%d\", this);\n            let year = cfmt::custom_formatter!(\"%y\", this);\n            write!(f, \"{}/{}/{}\", month, day, year)\n        }\n    }\n});\n\n// Dynamic format specifiers, checked at runtime\nimpl cfmt::runtime::CustomFormat for DateTime {\n    fn fmt(\u0026self, f: \u0026mut fmt::Formatter, spec: \u0026str) -\u003e fmt::Result {\n        let mut chars = spec.chars();\n        match (chars.next(), chars.next_back()) {\n            // Nanoseconds with n digits (%nN)\n            (Some('%'), Some('N')) =\u003e match chars.as_str().parse() {\n                Ok(n) if n \u003e 0 =\u003e {\n                    if n \u003c= 9 {\n                        write!(f, \"{:0width$}\", self.nanoseconds / 10u32.pow(9 - n as u32), width = n)\n                    } else {\n                        write!(f, \"{:09}{:0width$}\", self.nanoseconds, 0, width = n - 9)\n                    }\n                }\n                _ =\u003e Err(fmt::Error),\n            },\n            _ =\u003e Err(fmt::Error),\n        }\n    }\n}\n\nlet dt = DateTime {\n    year: 1836,\n    month: 5,\n    month_day: 18,\n    hour: 23,\n    minute: 45,\n    second: 54,\n    nanoseconds: 123456789,\n};\n\n// Expands to:\n//\n// match (\u0026(\"DateTime\"), \u0026dt) {\n//     (arg0, arg1) =\u003e ::std::println!(\n//         \"The {0:?} is: {1}-{2}-{3} {4}:{5}:{6}.{7}\",\n//         arg0,\n//         ::custom_format::custom_formatter!(\"%Y\", arg1),\n//         ::custom_format::custom_formatter!(\"%m\", arg1),\n//         ::custom_format::custom_formatter!(\"%d\", arg1),\n//         ::custom_format::custom_formatter!(\"%H\", arg1),\n//         ::custom_format::custom_formatter!(\"%M\", arg1),\n//         ::custom_format::custom_formatter!(\"%S\", arg1),\n//         ::custom_format::runtime::CustomFormatter::new(\"%6N\", arg1)\n//     ),\n// }\n//\n// Output: `The \"DateTime\" is: 1836-05-18 23:45:54.123456`\n//\n// The custom format specifier is interpreted as a compile-time specifier by default,\n// or as a runtime specifier if it is inside \"\u003c\u003e\".\ncfmt::println!(\n    \"The {ty:?} is: {dt :%Y}-{dt :%m}-{dt :%d} {dt :%H}:{dt :%M}:{dt :%S}.{dt :\u003c%6N\u003e}\",\n    ty = \"DateTime\",\n);\n\n// Compile-time error since \"%h\" is not a valid format specifier\n// cfmt::println!(\"{0 :%h}\", dt);\n\n// Panic at runtime since \"%h\" is not a valid format specifier\n// cfmt::println!(\"{0 :\u003c%h\u003e}\", dt);\n```\n\n\u003c/details\u003e\n\n## Compiler support\n\nRequires `rustc 1.56+`.\n\n## License\n\nThis project is licensed under either of\n\n- [Apache License, Version 2.0](https://github.com/x-hgg-x/custom-format/blob/master/LICENSE-Apache)\n- [MIT license](https://github.com/x-hgg-x/custom-format/blob/master/LICENSE-MIT)\n\nat your option.\n\nUnless you explicitly state otherwise, any contribution intentionally submitted for inclusion in\nthis project by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any\nadditional terms or conditions.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fx-hgg-x%2Fcustom-format","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fx-hgg-x%2Fcustom-format","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fx-hgg-x%2Fcustom-format/lists"}