diff options
Diffstat (limited to 'third_party/rust/cstr')
21 files changed, 505 insertions, 0 deletions
diff --git a/third_party/rust/cstr/.cargo-checksum.json b/third_party/rust/cstr/.cargo-checksum.json new file mode 100644 index 0000000000..9d9ca8aff4 --- /dev/null +++ b/third_party/rust/cstr/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{"Cargo.toml":"9766da0dcd235f8d0d4ebdc925050558710adfd4495c123b1f4997666869d524","LICENSE":"5a9bf0e7661617253ca7c12313f51a96aa62dec0bcd15a59c533c88b8093d124","README.md":"8fdfa924e95d7a83f3c032dcc103cb411743c404e7e080b985c97b5db90eea24","src/lib.rs":"ad266f1d5c682943741344d84dba39c516c3b8b26b34a4ff2c858de9934cdfe5","src/parse.rs":"19214fac49af5852b93a37d43af6ee93e62a1e95e3a629f8d5da254925b7d294","tests/clippy_lints.rs":"4398124cd5bc3a7f295f6203d543fc7d99abfd945eb7418ccfa60535586d7e37","tests/compile_fail/empty.rs":"52dc3c0d4d6ee0bd6d89a34d1caf38d159830401f24ba30f5655f9de92697903","tests/compile_fail/empty.stderr":"dbcf3dab8a8638b833df9089d9bc9ff7494f39dbb91e94bdd769912678ccf7f8","tests/compile_fail/interior-nul.rs":"ecc09440020287377ca18e4b8308d1d516620a87612a5381bafc01fe48734d34","tests/compile_fail/interior-nul.stderr":"8bd003a7dfff248411403bdf666f8a0631307f468d589cf01e475b062db4b101","tests/compile_fail/non-str.rs":"e08be18a524a4482fb7f34cbc6e8448a878b41cf2c26dea99268aaabab6c3f3f","tests/compile_fail/non-str.stderr":"8dff245264d9c69dc151f742542a72400d7422f2a0f2b133a9f4d4fc96a4016a","tests/compile_fail/trash-after.rs":"7dff7a301c9087984c5acda183e34492f3d0f2ebec14b8dc0d2b11aab972a111","tests/compile_fail/trash-after.stderr":"487b5d6b687c52b80f9d9cba691a8654067a88f7d03d2d952d7e97d610ab70f3","tests/compile_test.rs":"13e3e0d22ec0dffa4d0be0c4db6381a03feff50cc25aa65c4950cc7e865d122d","tests/pass/byte_str_lit.rs":"9085e1f1e67dae193d33ff59c253cac23c9e23e9d8c7f92f0aba99097ade132e","tests/pass/const.rs":"777aeb93c3030349529a41ac62b3577b36badc4bada4ec46e45b5055d3676dbd","tests/pass/ident.rs":"5116ee71578d479d899345e039e5955b5dee442234dc504e1a9bfb9260cf8f15","tests/pass/macro.rs":"9596c936ed4d963fb40459ecd98b60610d3d90e41918f350ff45b6129b1aa0b7","tests/pass/str_lit.rs":"955fb887ebc01538bafe10fa810381eb53aebaafb8b36053e8712c081862fe7a"},"package":"8aa998c33a6d3271e3678950a22134cd7dd27cef86dee1b611b5b14207d1d90b"}
\ No newline at end of file diff --git a/third_party/rust/cstr/Cargo.toml b/third_party/rust/cstr/Cargo.toml new file mode 100644 index 0000000000..712f393718 --- /dev/null +++ b/third_party/rust/cstr/Cargo.toml @@ -0,0 +1,41 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g., crates.io) dependencies. +# +# If you are reading this file be aware that the original Cargo.toml +# will likely look very different (and much more reasonable). +# See Cargo.toml.orig for the original contents. + +[package] +edition = "2018" +rust-version = "1.64" +name = "cstr" +version = "0.2.11" +authors = ["Xidorn Quan <me@upsuper.org>"] +description = "Macro for building static CStr reference" +readme = "README.md" +keywords = [ + "macro", + "cstr", +] +license = "MIT" +repository = "https://github.com/upsuper/cstr" + +[lib] +proc-macro = true + +[dependencies.proc-macro2] +version = "1" + +[dependencies.quote] +version = "1" + +[dev-dependencies.trybuild] +version = "1.0.30" + +[badges.travis-ci] +branch = "master" +repository = "upsuper/cstr" diff --git a/third_party/rust/cstr/LICENSE b/third_party/rust/cstr/LICENSE new file mode 100644 index 0000000000..82ec98b7cc --- /dev/null +++ b/third_party/rust/cstr/LICENSE @@ -0,0 +1,25 @@ +Copyright (c) 2018-2020 Xidorn Quan + +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/third_party/rust/cstr/README.md b/third_party/rust/cstr/README.md new file mode 100644 index 0000000000..7ee3ba2474 --- /dev/null +++ b/third_party/rust/cstr/README.md @@ -0,0 +1,30 @@ +# cstr + +[![CI](https://github.com/upsuper/cstr/workflows/CI/badge.svg)](https://github.com/upsuper/cstr/actions) +[![Crates.io](https://img.shields.io/crates/v/cstr.svg)](https://crates.io/crates/cstr) +[![Docs](https://docs.rs/cstr/badge.svg)](https://docs.rs/cstr) + +<!-- cargo-sync-readme start --> + +A macro for getting `&'static CStr` from literal or identifier. + +This macro checks whether the given literal is valid for `CStr` +at compile time, and returns a static reference of `CStr`. + +This macro can be used to to initialize constants on Rust 1.64 and above. + +## Example + +```rust +use cstr::cstr; +use std::ffi::CStr; + +let test = cstr!(b"hello\xff"); +assert_eq!(test, CStr::from_bytes_with_nul(b"hello\xff\0").unwrap()); +let test = cstr!("hello"); +assert_eq!(test, CStr::from_bytes_with_nul(b"hello\0").unwrap()); +let test = cstr!(hello); +assert_eq!(test, CStr::from_bytes_with_nul(b"hello\0").unwrap()); +``` + +<!-- cargo-sync-readme end --> diff --git a/third_party/rust/cstr/src/lib.rs b/third_party/rust/cstr/src/lib.rs new file mode 100644 index 0000000000..c9e69d924c --- /dev/null +++ b/third_party/rust/cstr/src/lib.rs @@ -0,0 +1,56 @@ +//! A macro for getting `&'static CStr` from literal or identifier. +//! +//! This macro checks whether the given literal is valid for `CStr` +//! at compile time, and returns a static reference of `CStr`. +//! +//! This macro can be used to to initialize constants on Rust 1.64 and above. +//! +//! ## Example +//! +//! ``` +//! use cstr::cstr; +//! use std::ffi::CStr; +//! +//! let test = cstr!(b"hello\xff"); +//! assert_eq!(test, CStr::from_bytes_with_nul(b"hello\xff\0").unwrap()); +//! let test = cstr!("hello"); +//! assert_eq!(test, CStr::from_bytes_with_nul(b"hello\0").unwrap()); +//! let test = cstr!(hello); +//! assert_eq!(test, CStr::from_bytes_with_nul(b"hello\0").unwrap()); +//! ``` + +// While this isn't necessary when using Cargo >= 1.42, omitting it actually requires path-less +// `--extern proc_macro` to be passed to `rustc` when building this crate. Some tools may not do +// this correctly. So it's added as a precaution. +extern crate proc_macro; + +use crate::parse::parse_input; +use proc_macro::TokenStream as RawTokenStream; +use proc_macro2::{Literal, Span, TokenStream}; +use quote::{quote, quote_spanned}; +use std::ffi::CString; + +mod parse; + +struct Error(Span, &'static str); + +#[proc_macro] +pub fn cstr(input: RawTokenStream) -> RawTokenStream { + let tokens = match build_byte_str(input.into()) { + Ok(s) => quote!(unsafe { ::core::ffi::CStr::from_bytes_with_nul_unchecked(#s) }), + Err(Error(span, msg)) => quote_spanned!(span => compile_error!(#msg)), + }; + tokens.into() +} + +fn build_byte_str(input: TokenStream) -> Result<Literal, Error> { + let (bytes, span) = parse_input(input)?; + match CString::new(bytes) { + Ok(s) => { + let mut lit = Literal::byte_string(s.as_bytes_with_nul()); + lit.set_span(span); + Ok(lit) + } + Err(_) => Err(Error(span, "nul byte found in the literal")), + } +} diff --git a/third_party/rust/cstr/src/parse.rs b/third_party/rust/cstr/src/parse.rs new file mode 100644 index 0000000000..aff419d654 --- /dev/null +++ b/third_party/rust/cstr/src/parse.rs @@ -0,0 +1,225 @@ +use crate::Error; +use proc_macro2::{Delimiter, Ident, Literal, Span, TokenStream, TokenTree}; +use std::char; + +macro_rules! unexpected_content { + () => { + "expected one of: byte string literal, string literal, identifier" + }; +} + +pub(crate) fn parse_input(mut input: TokenStream) -> Result<(Vec<u8>, Span), Error> { + loop { + let mut tokens = input.into_iter(); + let token = match tokens.next() { + Some(token) => token, + None => { + return Err(Error( + Span::call_site(), + concat!("unexpected end of input, ", unexpected_content!()), + )) + } + }; + let span = token.span(); + let result = match token { + // Unwrap any empty group which may be created from macro expansion. + TokenTree::Group(group) if group.delimiter() == Delimiter::None => Err(group), + TokenTree::Literal(literal) => match parse_literal(literal) { + Ok(result) => Ok(result), + Err(msg) => return Err(Error(span, msg)), + }, + TokenTree::Ident(ident) => Ok(parse_ident(ident)), + _ => return Err(Error(span, unexpected_content!())), + }; + if let Some(token) = tokens.next() { + return Err(Error(token.span(), "unexpected token")); + } + match result { + Ok(result) => return Ok((result, span)), + Err(group) => input = group.stream(), + } + } +} + +fn parse_literal(literal: Literal) -> Result<Vec<u8>, &'static str> { + let s = literal.to_string(); + let s = s.as_bytes(); + match s[0] { + b'"' => Ok(parse_cooked_content(s)), + b'r' => Ok(parse_raw_content(&s[1..])), + b'b' => match s[1] { + b'"' => Ok(parse_cooked_content(&s[1..])), + b'r' => Ok(parse_raw_content(&s[2..])), + _ => Err(unexpected_content!()), + }, + _ => Err(unexpected_content!()), + } +} + +fn all_pounds(bytes: &[u8]) -> bool { + bytes.iter().all(|b| *b == b'#') +} + +/// Parses raw string / bytes content after `r` prefix. +fn parse_raw_content(s: &[u8]) -> Vec<u8> { + let q_start = s.iter().position(|b| *b == b'"').unwrap(); + let q_end = s.iter().rposition(|b| *b == b'"').unwrap(); + assert!(all_pounds(&s[0..q_start])); + assert!(all_pounds(&s[q_end + 1..q_end + q_start + 1])); + Vec::from(&s[q_start + 1..q_end]) +} + +/// Parses the cooked string / bytes content within quotes. +fn parse_cooked_content(mut s: &[u8]) -> Vec<u8> { + s = &s[1..s.iter().rposition(|b| *b == b'"').unwrap()]; + let mut result = Vec::new(); + while !s.is_empty() { + match s[0] { + b'\\' => {} + b'\r' => { + assert_eq!(s[1], b'\n'); + result.push(b'\n'); + s = &s[2..]; + continue; + } + b => { + result.push(b); + s = &s[1..]; + continue; + } + } + let b = s[1]; + s = &s[2..]; + match b { + b'x' => { + let (b, rest) = backslash_x(s); + result.push(b); + s = rest; + } + b'u' => { + let (c, rest) = backslash_u(s); + result.extend_from_slice(c.encode_utf8(&mut [0; 4]).as_bytes()); + s = rest; + } + b'n' => result.push(b'\n'), + b'r' => result.push(b'\r'), + b't' => result.push(b'\t'), + b'\\' => result.push(b'\\'), + b'0' => result.push(b'\0'), + b'\'' => result.push(b'\''), + b'"' => result.push(b'"'), + b'\r' | b'\n' => { + let next = s.iter().position(|b| { + let ch = char::from_u32(u32::from(*b)).unwrap(); + !ch.is_whitespace() + }); + match next { + Some(pos) => s = &s[pos..], + None => s = b"", + } + } + b => panic!("unexpected byte {:?} after \\", b), + } + } + result +} + +fn backslash_x(s: &[u8]) -> (u8, &[u8]) { + let ch = hex_to_u8(s[0]) * 0x10 + hex_to_u8(s[1]); + (ch, &s[2..]) +} + +fn hex_to_u8(b: u8) -> u8 { + match b { + b'0'..=b'9' => b - b'0', + b'a'..=b'f' => b - b'a' + 10, + b'A'..=b'F' => b - b'A' + 10, + _ => unreachable!("unexpected non-hex character {:?} after \\x", b), + } +} + +fn backslash_u(s: &[u8]) -> (char, &[u8]) { + assert_eq!(s[0], b'{'); + let end = s[1..].iter().position(|b| *b == b'}').unwrap(); + let mut ch = 0; + for b in &s[1..=end] { + ch *= 0x10; + ch += u32::from(hex_to_u8(*b)); + } + (char::from_u32(ch).unwrap(), &s[end + 2..]) +} + +fn parse_ident(ident: Ident) -> Vec<u8> { + ident.to_string().into_bytes() +} + +#[cfg(test)] +mod tests { + use super::*; + use std::str::FromStr; + + // Tests below were modified from + // https://github.com/dtolnay/syn/blob/cd5fdc0f530f822446fccaf831669cd0cf4a0fc9/tests/test_lit.rs + + fn lit(s: &str) -> Vec<u8> { + match TokenStream::from_str(s) + .unwrap() + .into_iter() + .next() + .unwrap() + { + TokenTree::Literal(lit) => parse_literal(lit).unwrap(), + _ => panic!(), + } + } + + #[test] + fn strings() { + #[track_caller] + fn test_string(s: &str, value: &[u8]) { + assert_eq!(lit(s), value); + } + + test_string("\"a\"", b"a"); + test_string("\"\\n\"", b"\n"); + test_string("\"\\r\"", b"\r"); + test_string("\"\\t\"", b"\t"); + test_string("\"🐕\"", b"\xf0\x9f\x90\x95"); // NOTE: This is an emoji + test_string("\"\\\"\"", b"\""); + test_string("\"'\"", b"'"); + test_string("\"\"", b""); + test_string("\"\\u{1F415}\"", b"\xf0\x9f\x90\x95"); + test_string( + "\"contains\nnewlines\\\nescaped newlines\"", + b"contains\nnewlinesescaped newlines", + ); + test_string("r\"raw\nstring\\\nhere\"", b"raw\nstring\\\nhere"); + test_string("\"...\"q", b"..."); + test_string("r\"...\"q", b"..."); + test_string("r##\"...\"##q", b"..."); + } + + #[test] + fn byte_strings() { + #[track_caller] + fn test_byte_string(s: &str, value: &[u8]) { + assert_eq!(lit(s), value); + } + + test_byte_string("b\"a\"", b"a"); + test_byte_string("b\"\\n\"", b"\n"); + test_byte_string("b\"\\r\"", b"\r"); + test_byte_string("b\"\\t\"", b"\t"); + test_byte_string("b\"\\\"\"", b"\""); + test_byte_string("b\"'\"", b"'"); + test_byte_string("b\"\"", b""); + test_byte_string( + "b\"contains\nnewlines\\\nescaped newlines\"", + b"contains\nnewlinesescaped newlines", + ); + test_byte_string("br\"raw\nstring\\\nhere\"", b"raw\nstring\\\nhere"); + test_byte_string("b\"...\"q", b"..."); + test_byte_string("br\"...\"q", b"..."); + test_byte_string("br##\"...\"##q", b"..."); + } +} diff --git a/third_party/rust/cstr/tests/clippy_lints.rs b/third_party/rust/cstr/tests/clippy_lints.rs new file mode 100644 index 0000000000..47d7f27e2b --- /dev/null +++ b/third_party/rust/cstr/tests/clippy_lints.rs @@ -0,0 +1,10 @@ +use cstr::cstr; +use std::ffi::CStr; + +#[test] +#[deny(clippy::transmute_ptr_to_ref)] +fn deny_transmute_ptr_to_ref() { + let s: &'static CStr = cstr!("foo\u{4e00}bar"); + let expected = b"foo\xe4\xb8\x80bar\0"; + assert_eq!(s, CStr::from_bytes_with_nul(expected).unwrap()); +} diff --git a/third_party/rust/cstr/tests/compile_fail/empty.rs b/third_party/rust/cstr/tests/compile_fail/empty.rs new file mode 100644 index 0000000000..0ac967273e --- /dev/null +++ b/third_party/rust/cstr/tests/compile_fail/empty.rs @@ -0,0 +1,5 @@ +use cstr::cstr; + +fn main() { + let _foo = cstr!(); +} diff --git a/third_party/rust/cstr/tests/compile_fail/empty.stderr b/third_party/rust/cstr/tests/compile_fail/empty.stderr new file mode 100644 index 0000000000..68bda07fab --- /dev/null +++ b/third_party/rust/cstr/tests/compile_fail/empty.stderr @@ -0,0 +1,7 @@ +error: unexpected end of input, expected one of: byte string literal, string literal, identifier + --> $DIR/empty.rs:4:16 + | +4 | let _foo = cstr!(); + | ^^^^^^^ + | + = note: this error originates in the macro `cstr` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/third_party/rust/cstr/tests/compile_fail/interior-nul.rs b/third_party/rust/cstr/tests/compile_fail/interior-nul.rs new file mode 100644 index 0000000000..a6876aeb1d --- /dev/null +++ b/third_party/rust/cstr/tests/compile_fail/interior-nul.rs @@ -0,0 +1,5 @@ +use cstr::cstr; + +fn main() { + let _foo = cstr!("foo\0bar"); +} diff --git a/third_party/rust/cstr/tests/compile_fail/interior-nul.stderr b/third_party/rust/cstr/tests/compile_fail/interior-nul.stderr new file mode 100644 index 0000000000..0c6ced1a45 --- /dev/null +++ b/third_party/rust/cstr/tests/compile_fail/interior-nul.stderr @@ -0,0 +1,5 @@ +error: nul byte found in the literal + --> $DIR/interior-nul.rs:4:22 + | +4 | let _foo = cstr!("foo\0bar"); + | ^^^^^^^^^^ diff --git a/third_party/rust/cstr/tests/compile_fail/non-str.rs b/third_party/rust/cstr/tests/compile_fail/non-str.rs new file mode 100644 index 0000000000..172b145590 --- /dev/null +++ b/third_party/rust/cstr/tests/compile_fail/non-str.rs @@ -0,0 +1,7 @@ +use cstr::cstr; + +fn main() { + let _foo = cstr!(1); + let _foo = cstr!(("a")); + let _foo = cstr!(&1); +} diff --git a/third_party/rust/cstr/tests/compile_fail/non-str.stderr b/third_party/rust/cstr/tests/compile_fail/non-str.stderr new file mode 100644 index 0000000000..bbbf7e7169 --- /dev/null +++ b/third_party/rust/cstr/tests/compile_fail/non-str.stderr @@ -0,0 +1,17 @@ +error: expected one of: byte string literal, string literal, identifier + --> $DIR/non-str.rs:4:22 + | +4 | let _foo = cstr!(1); + | ^ + +error: expected one of: byte string literal, string literal, identifier + --> $DIR/non-str.rs:5:22 + | +5 | let _foo = cstr!(("a")); + | ^^^^^ + +error: expected one of: byte string literal, string literal, identifier + --> $DIR/non-str.rs:6:22 + | +6 | let _foo = cstr!(&1); + | ^ diff --git a/third_party/rust/cstr/tests/compile_fail/trash-after.rs b/third_party/rust/cstr/tests/compile_fail/trash-after.rs new file mode 100644 index 0000000000..5e4f7c3f08 --- /dev/null +++ b/third_party/rust/cstr/tests/compile_fail/trash-after.rs @@ -0,0 +1,5 @@ +use cstr::cstr; + +fn main() { + let _foo = cstr!("foo" + "bar"); +} diff --git a/third_party/rust/cstr/tests/compile_fail/trash-after.stderr b/third_party/rust/cstr/tests/compile_fail/trash-after.stderr new file mode 100644 index 0000000000..d6bb1530af --- /dev/null +++ b/third_party/rust/cstr/tests/compile_fail/trash-after.stderr @@ -0,0 +1,5 @@ +error: unexpected token + --> $DIR/trash-after.rs:4:28 + | +4 | let _foo = cstr!("foo" + "bar"); + | ^ diff --git a/third_party/rust/cstr/tests/compile_test.rs b/third_party/rust/cstr/tests/compile_test.rs new file mode 100644 index 0000000000..b3b9d9f6ce --- /dev/null +++ b/third_party/rust/cstr/tests/compile_test.rs @@ -0,0 +1,6 @@ +#[test] +fn compile_test() { + let t = trybuild::TestCases::new(); + t.pass("tests/pass/*.rs"); + t.compile_fail("tests/compile_fail/*.rs"); +} diff --git a/third_party/rust/cstr/tests/pass/byte_str_lit.rs b/third_party/rust/cstr/tests/pass/byte_str_lit.rs new file mode 100644 index 0000000000..fd87f176c2 --- /dev/null +++ b/third_party/rust/cstr/tests/pass/byte_str_lit.rs @@ -0,0 +1,7 @@ +use cstr::cstr; +use std::ffi::CStr; + +fn main() { + let foo: &'static CStr = cstr!(b"foo\xffbar"); + assert_eq!(foo, CStr::from_bytes_with_nul(b"foo\xffbar\0").unwrap()); +} diff --git a/third_party/rust/cstr/tests/pass/const.rs b/third_party/rust/cstr/tests/pass/const.rs new file mode 100644 index 0000000000..ae8647b954 --- /dev/null +++ b/third_party/rust/cstr/tests/pass/const.rs @@ -0,0 +1,10 @@ +use cstr::cstr; +use std::ffi::CStr; + +const FOO: &CStr = cstr!(b"foo\xffbar"); +static BAR: &CStr = cstr!("bar"); + +fn main() { + assert_eq!(FOO, CStr::from_bytes_with_nul(b"foo\xffbar\0").unwrap()); + assert_eq!(BAR, CStr::from_bytes_with_nul(b"bar\0").unwrap()); +} diff --git a/third_party/rust/cstr/tests/pass/ident.rs b/third_party/rust/cstr/tests/pass/ident.rs new file mode 100644 index 0000000000..55e41c8621 --- /dev/null +++ b/third_party/rust/cstr/tests/pass/ident.rs @@ -0,0 +1,9 @@ +use cstr::cstr; +use std::ffi::CStr; + +fn main() { + let foo: &'static CStr = cstr!(foobar); + assert_eq!(foo, CStr::from_bytes_with_nul(b"foobar\0").unwrap()); + let foo: &'static CStr = cstr!(r#foobar); + assert_eq!(foo, CStr::from_bytes_with_nul(b"r#foobar\0").unwrap()); +} diff --git a/third_party/rust/cstr/tests/pass/macro.rs b/third_party/rust/cstr/tests/pass/macro.rs new file mode 100644 index 0000000000..e89deac648 --- /dev/null +++ b/third_party/rust/cstr/tests/pass/macro.rs @@ -0,0 +1,21 @@ +use cstr::cstr; +use std::ffi::CStr; + +macro_rules! cstr_expr { + ($s:expr) => { + cstr!($s) + }; +} + +macro_rules! cstr_literal { + ($s:literal) => { + cstr!($s) + }; +} + +fn main() { + let foo: &'static CStr = cstr_expr!("foo"); + assert_eq!(foo, CStr::from_bytes_with_nul(b"foo\0").unwrap()); + let bar: &'static CStr = cstr_literal!("bar"); + assert_eq!(bar, CStr::from_bytes_with_nul(b"bar\0").unwrap()); +} diff --git a/third_party/rust/cstr/tests/pass/str_lit.rs b/third_party/rust/cstr/tests/pass/str_lit.rs new file mode 100644 index 0000000000..d925859a9a --- /dev/null +++ b/third_party/rust/cstr/tests/pass/str_lit.rs @@ -0,0 +1,8 @@ +use cstr::cstr; +use std::ffi::CStr; + +fn main() { + let foo: &'static CStr = cstr!("foo\u{4e00}bar"); + let expected = b"foo\xe4\xb8\x80bar\0"; + assert_eq!(foo, CStr::from_bytes_with_nul(expected).unwrap()); +} |