{"id":22297480,"url":"https://github.com/rustonaut/soft-ascii-string","last_synced_at":"2026-03-11T05:31:24.354Z","repository":{"id":57667912,"uuid":"107148256","full_name":"rustonaut/soft-ascii-string","owner":"rustonaut","description":"A wrapper around String/str/char with an is-ascii soft constraint, a violation is no rust safety violation \"just\" a bug","archived":false,"fork":false,"pushed_at":"2020-02-01T13:38:59.000Z","size":41,"stargazers_count":2,"open_issues_count":0,"forks_count":1,"subscribers_count":3,"default_branch":"master","last_synced_at":"2025-12-14T03:37:37.948Z","etag":null,"topics":[],"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/rustonaut.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}},"created_at":"2017-10-16T15:40:08.000Z","updated_at":"2020-06-01T06:45:15.000Z","dependencies_parsed_at":"2022-09-07T15:41:49.936Z","dependency_job_id":null,"html_url":"https://github.com/rustonaut/soft-ascii-string","commit_stats":null,"previous_names":["dac-gmbh/soft-ascii-string"],"tags_count":3,"template":false,"template_full_name":null,"purl":"pkg:github/rustonaut/soft-ascii-string","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rustonaut%2Fsoft-ascii-string","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rustonaut%2Fsoft-ascii-string/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rustonaut%2Fsoft-ascii-string/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rustonaut%2Fsoft-ascii-string/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/rustonaut","download_url":"https://codeload.github.com/rustonaut/soft-ascii-string/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rustonaut%2Fsoft-ascii-string/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":30372169,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-03-10T21:41:54.280Z","status":"online","status_checked_at":"2026-03-11T02:00:07.027Z","response_time":84,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","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-12-03T17:49:55.280Z","updated_at":"2026-03-11T05:31:24.321Z","avatar_url":"https://github.com/rustonaut.png","language":"Rust","funding_links":[],"categories":[],"sub_categories":[],"readme":"soft-ascii-string [![Crates.io](https://img.shields.io/crates/v/soft-ascii-string.svg)](https://crates.io/crates/soft-ascii-string) [![soft-ascii-string](https://docs.rs/soft-ascii-string/badge.svg)](https://docs.rs/soft-ascii-string) [![License](https://img.shields.io/badge/License-MIT-blue.svg)](https://opensource.org/licenses/MIT) [![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://opensource.org/licenses/Apache-2.0)\n=============\n\nsoft-ascii-string provides char, str and string wrapper which\nadd an \"is-ascii\" soft constraint.\n\nAs it is a soft constraint it can be violated, while a violation\nis (normally) a bug it _does not_ introduce any safety issues.\nIn this soft-ascii-string differs to e.g. [ascii](https://crates.io/crates/ascii)\nwhich uses a hard constraint and where a violation does brake\nrust safety and potentially introduces undefined behavior.\n\nSoft-ascii-string is suited for situations where many places\n(e.g. external libraries) output strings which should be\nascii and which you do not want to iterate over to assure\nthey are ascii but where you neither want to use a unsafe\nconversions as it would be required by the ascii crate.\n\nThis crate is not necessarily suited if you want to rally on the string\nbeing ascii on a safety level, you might want to consider using\n[ascii](https://crates.io/crates/ascii) in that case.\n\nDocumentation can be [viewed on docs.rs](https://docs.rs/soft-ascii-string).\n\nExample\n-------\n\n```rust\nextern crate soft_ascii_string;\n\nuse soft_ascii_string::{SoftAsciiChar, SoftAsciiStr, SoftAsciiString};\n\nfn main() {\n    // encoder_stub should encode all non-ascii chars\n    // but it's a complex external dependency so we do\n    // not want to rely on it on a safety level\n    let mut ascii = SoftAsciiString::from_unchecked(external::encoder_stub(\"magic↓\"));\n\n    // we know \":\" is ascii so no unnecessary checks here\n    ascii.push(SoftAsciiChar::from_unchecked(':'));\n    // we know \"abcde\" is ascii so no unnecessary checks here\n    ascii.push_str(SoftAsciiStr::from_unchecked(\"abcde\"));\n\n    // lets assume we got this from somewhere\n    let other_input = \"other string\";\n    let part = SoftAsciiStr::from_str(other_input)\n        .expect(\"other_input should have been ascii\");\n    ascii.push_str(part);\n\n    let mut clone = SoftAsciiString::with_capacity(ascii.len());\n    // the chars(), char_indices() operators return a\n    // iterator returning SoftAsciiChars\n    for ch in ascii.chars() {\n        clone.push(ch);\n    }\n\n    // we do all kind of cost transformations\n    // without having to revalidate that it is\n    // ascii as long as we do not want to rely on it\n    internal::costy_transformations(\u0026mut ascii);\n\n    // when running unsafe code we really do not want a bug\n    // which introduced non ascii code to introduce unsafety\n    // so we can just validate if it really is ascii.\n    // On the other hand as long as we do not need a 100% guarantee\n    // for security reason we do not need to call revalidate.\n    match ascii.revalidate_soft_constraint() {\n        Ok(ascii) =\u003e {\n            unsafe {external::requires_ascii(ascii.as_bytes())}\n        },\n        Err(err) =\u003e panic!(\"non-ascii content in ascii string\")\n    }\n\n}\n\n\nmod internal {\n    use soft_ascii_string::SoftAsciiString;\n\n    pub fn costy_transformations(s: \u0026mut SoftAsciiString) {\n        let s2 = s.clone();\n        s.insert_str(0, \u0026*s2)\n    }\n}\n\nmod external {\n\n    // lets assume this is an external function only working with ascii\n    pub unsafe fn requires_ascii(b: \u0026[u8])  {}\n\n    // lets assume this is more complex and\n    // from a external dependency, we assume\n    // it returns ascii, but what if there is\n    // a bug\n    pub fn encoder_stub(s: \u0026str) -\u003e String {\n        let mut out = String::with_capacity(s.len());\n        for ch in s.chars() {\n            if ' ' \u003c= ch \u0026\u0026 ch \u003c= '~' {\n                out.push(ch)\n            } else { out.push('?') }\n        }\n        out\n    }\n\n}\n```\n\nError handling:\n\n```rust\nextern crate soft_ascii_string;\n\nuse soft_ascii_string::{SoftAsciiChar, SoftAsciiStr, SoftAsciiString};\n\nfn main() {\n    let non_ascii_input: String = \"←↓↓↓\".into();\n    match SoftAsciiString::from_string(non_ascii_input) {\n        Ok(ok_value) =\u003e panic!(\"the string should not have been ascii\"),\n        Err(err) =\u003e {\n            let original_source: String = err.into_source();\n            println!(\"the input was: {:?}\", original_source)\n        }\n    }\n}\n```\n\nLicense\n-------\n\nLicensed under either of\n\n- Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0)\n- MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT)\n\nat your option.\n\nContribution\n------------\n\nUnless you explicitly state otherwise, any contribution intentionally submitted\nfor inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any\nadditional terms or conditions.\n\nChange Log\n----------\n\n- `v1.0`\n  - added `from_unchecked` to `SoftAsciiChar`, `SoftAsciiStr`, `SoftAsciiString`\n  - deprecated `from_char_unchecked`, `from_str_unchecked`, `from_string_unchecked`\n\n- `v1.0.1`\n  - updated metadata (author email, repository link and maintenance badge)\n\n- `v1.1.0`\n  - added `#[repr(transparent)]` (thanks to lo48576/YOSHIOKA Takuma)\n  - deprecated `trim_left`,`trim_right`,`slice_unchecked`\n  - added `trim_start`,`trim_end`, `get_unchecked` (limited to `Range*\u003cusize\u003e`\n    and `RangeFull` indices).","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frustonaut%2Fsoft-ascii-string","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Frustonaut%2Fsoft-ascii-string","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frustonaut%2Fsoft-ascii-string/lists"}