#ascii-text #string #ascii #safe

soft-ascii-string

char/str/string 包装器,增加 "is-ascii" 软约束

6 个版本 (3 个稳定)

使用旧的 Rust 2015

1.1.0 2020年2月1日
1.0.1 2019年10月11日
1.0.0 2018年6月11日
0.2.0 2018年1月9日
0.1.0 2017年11月7日

#677 in 文本处理

Download history 38/week @ 2024-03-11 40/week @ 2024-03-18 39/week @ 2024-03-25 83/week @ 2024-04-01 26/week @ 2024-04-08 42/week @ 2024-04-15 48/week @ 2024-04-22 31/week @ 2024-04-29 48/week @ 2024-05-06 42/week @ 2024-05-13 35/week @ 2024-05-20 47/week @ 2024-05-27 37/week @ 2024-06-03 39/week @ 2024-06-10 30/week @ 2024-06-17 30/week @ 2024-06-24

每月139次下载
用于 11 个 Crates (8 个直接)

MIT/Apache

51KB
1.5K SLoC

soft-ascii-string Crates.io soft-ascii-string License License

soft-ascii-string 提供了 char、str 和 string 包装器,增加了 "is-ascii" 软约束。

由于这是一个软约束,它可以被违反,而违反通常是一个错误,但它 不会 引入任何安全问题。在这点上,soft-ascii-string 与例如 ascii 不同,ascii 使用硬约束,违反约束会破坏 Rust 的安全性,并可能引入未定义的行为。

Soft-ascii-string 适用于许多地方(例如外部库)输出应该是 ASCII 的字符串,你不想遍历以确保它们是 ASCII,但你也不想使用 unsafe 转换,因为这会要求使用 ascii crate。

如果你想在安全级别上确保字符串是 ASCII,这个 crate 并不一定适合你,你可能需要考虑在这种情况下使用 ascii

文档可以在 docs.rs 上查看。

示例

extern crate soft_ascii_string;

use soft_ascii_string::{SoftAsciiChar, SoftAsciiStr, SoftAsciiString};

fn main() {
    // encoder_stub should encode all non-ascii chars
    // but it's a complex external dependency so we do
    // not want to rely on it on a safety level
    let mut ascii = SoftAsciiString::from_unchecked(external::encoder_stub("magic↓"));

    // we know ":" is ascii so no unnecessary checks here
    ascii.push(SoftAsciiChar::from_unchecked(':'));
    // we know "abcde" is ascii so no unnecessary checks here
    ascii.push_str(SoftAsciiStr::from_unchecked("abcde"));

    // lets assume we got this from somewhere
    let other_input = "other string";
    let part = SoftAsciiStr::from_str(other_input)
        .expect("other_input should have been ascii");
    ascii.push_str(part);

    let mut clone = SoftAsciiString::with_capacity(ascii.len());
    // the chars(), char_indices() operators return a
    // iterator returning SoftAsciiChars
    for ch in ascii.chars() {
        clone.push(ch);
    }

    // we do all kind of cost transformations
    // without having to revalidate that it is
    // ascii as long as we do not want to rely on it
    internal::costy_transformations(&mut ascii);

    // when running unsafe code we really do not want a bug
    // which introduced non ascii code to introduce unsafety
    // so we can just validate if it really is ascii.
    // On the other hand as long as we do not need a 100% guarantee
    // for security reason we do not need to call revalidate.
    match ascii.revalidate_soft_constraint() {
        Ok(ascii) => {
            unsafe {external::requires_ascii(ascii.as_bytes())}
        },
        Err(err) => panic!("non-ascii content in ascii string")
    }

}


mod internal {
    use soft_ascii_string::SoftAsciiString;

    pub fn costy_transformations(s: &mut SoftAsciiString) {
        let s2 = s.clone();
        s.insert_str(0, &*s2)
    }
}

mod external {

    // lets assume this is an external function only working with ascii
    pub unsafe fn requires_ascii(b: &[u8])  {}

    // lets assume this is more complex and
    // from a external dependency, we assume
    // it returns ascii, but what if there is
    // a bug
    pub fn encoder_stub(s: &str) -> String {
        let mut out = String::with_capacity(s.len());
        for ch in s.chars() {
            if ' ' <= ch && ch <= '~' {
                out.push(ch)
            } else { out.push('?') }
        }
        out
    }

}

错误处理

extern crate soft_ascii_string;

use soft_ascii_string::{SoftAsciiChar, SoftAsciiStr, SoftAsciiString};

fn main() {
    let non_ascii_input: String = "←↓↓↓".into();
    match SoftAsciiString::from_string(non_ascii_input) {
        Ok(ok_value) => panic!("the string should not have been ascii"),
        Err(err) => {
            let original_source: String = err.into_source();
            println!("the input was: {:?}", original_source)
        }
    }
}

许可协议

根据您选择以下其中一项许可协议

任选其一。

贡献

除非您明确声明,否则根据 Apache-2.0 许可协议定义,您有意提交的任何贡献,都将按照上述方式双重许可,不附加任何额外条款或条件。

变更日志

  • v1.0
    • SoftAsciiCharSoftAsciiStrSoftAsciiString 添加了 from_unchecked
    • 弃用了 from_char_uncheckedfrom_str_uncheckedfrom_string_unchecked

无运行时依赖