const_cstr_fork/
lib.rs

1// Copyright (c) 2015 const-cstr developers
2// Copyright (c) 2017 const-cstr-fork developers
3// Licensed under the Apache License, Version 2.0
4// <LICENSE-APACHE or
5// http://www.apache.org/licenses/LICENSE-2.0> or the MIT
6// license <LICENSE-MIT or http://opensource.org/licenses/MIT>,
7// at your option. All files in the project carrying such
8// notice may not be copied, modified, or distributed except
9// according to those terms.
10//! Create static C-compatible strings from Rust string literals.
11//! 
12//! Example
13//! -------
14//!
15//! ```rust
16//! #[macro_use] extern crate const_cstr_fork;
17//! // Just for the `libc::c_char` type alias.
18//! extern crate libc;
19//!     
20//! use std::ffi::CStr;
21//!
22//! const_cstr! {
23//!     HELLO_CSTR = "Hello, world!";
24//!
25//!     // Multiple declarations can be made with one invocation.
26//!     // GOODNIGHT_CSTR = "Goodnight, sun!";
27//!
28//!     // But only with the same visibility:
29//!     // pub GOODNIGHT_CSTR = "Goodnight, sun!";
30//!     // ^~~ Error: expected identifier, found `pub` 
31//! }
32//!
33//! // Imagine this is an `extern "C"` function linked from some other lib.
34//! unsafe fn print_c_string(cstr: *const libc::c_char) {
35//!     println!("{}", CStr::from_ptr(cstr).to_str().unwrap());
36//! }
37//!
38//! fn main() {
39//!     // When just passed a literal, returns an rvalue instead.
40//!     let goodnight_cstr = const_cstr!("Goodnight, sun!");
41//!
42//!     unsafe {
43//!         print_c_string(HELLO_CSTR.as_ptr());
44//!         print_c_string(goodnight_cstr.as_ptr());
45//!     }
46//! }
47//! ```
48//!
49//! Prints:
50//!
51//! ```notest
52//! Hello, world!
53//! Goodnight, sun!
54//! ```
55
56#![allow(non_snake_case)]
57
58extern crate libc;
59
60use std::ffi::CStr;
61
62pub trait ToPointerCString
63{
64	#[inline(always)]
65	fn to_ptr(&self) -> *const ::libc::c_char;
66}
67
68/// A type representing a static C-compatible string.
69///
70/// Note
71/// ----
72/// Use ONLY the `const_cstr!` macro to create an instance of this struct.
73/// The macro will include the NUL byte for you.
74#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
75pub struct ConstCStr {
76    /// The wrapped string value. Not intended to be used for manual initialization.
77    /// Public only to allow initialization by the `const_cstr!` macro.
78    ///
79    /// Includes the NUL terminating byte. Use `to_str()` to get an `&'static str`
80    /// without the NUL terminating byte.
81    pub cValue: &'static str,
82	
83	/// Excludes the terminating byte
84	pub rustValue: &'static str,
85}
86
87impl ToPointerCString for ConstCStr
88{
89	#[inline(always)]
90	fn to_ptr(&self) -> *const ::libc::c_char
91	{
92		self.as_ptr()
93	}
94}
95
96impl ToPointerCString for CStr
97{	
98	#[inline(always)]
99	fn to_ptr(&self) -> *const ::libc::c_char
100	{
101		self.as_ptr() as *const ::libc::c_char
102	}
103}
104
105impl ConstCStr {
106    /// Returns the wrapped string, without the NUL terminating byte.
107    ///
108    /// Compare to `CStr::to_str()` which checks that the string is valid UTF-8 first,
109    /// since it starts from an arbitrary pointer instead of a Rust string slice.
110	#[inline(always)]
111    pub fn to_str(&self) -> &'static str {
112        self.rustValue
113    }
114
115    /// Returns the wrapped string as a byte slice, **without** the NUL terminating byte.
116	#[inline(always)]
117    pub fn to_bytes(&self) -> &'static [u8] {
118        self.rustValue.as_bytes()
119    }
120
121    /// Returns the wrapped string as a byte slice, *with** the NUL terminating byte.
122	#[inline(always)]
123    pub fn to_bytes_with_nul(&self) -> &'static [u8] {
124        self.cValue.as_bytes()
125    }
126
127    /// Returns a pointer to the beginning of the wrapped string.
128    ///
129    /// Suitable for passing to any function that expects a C-compatible string. 
130    /// Since the underlying string is guaranteed to be `'static`, 
131    /// the pointer should always be valid.
132	#[inline(always)]
133    pub fn as_ptr(&self) -> *const libc::c_char {
134		self.cValue.as_ptr() as *const libc::c_char
135    }
136
137    /// Returns the wrapped string as an `&'static CStr`, skipping the length check that
138    /// `CStr::from_ptr()` performs (since we know the length already).
139	#[inline(always)]
140    pub fn as_cstr(&self) -> &'static CStr {
141        unsafe {
142            CStr::from_ptr(self.cValue.as_ptr() as *const i8)
143        }
144    }
145}
146
147/// Create a C-compatible string as an rvalue or a `const` binding.
148/// Appends a NUL byte to the passed string.
149///
150/// Multiple `const` declarations can be created with one invocation, but only with the same
151/// visibility (`pub` or not).
152///
153/// See crate root documentation for example usage.
154///
155/// Note
156/// ----
157/// For logical consistency, the passed string(s) should not contain any NUL bytes.
158/// Remember that functions consuming a C-string will only see up to the first NUL byte.
159#[macro_export]
160macro_rules! const_cstr {
161    ($strval:expr) => (
162        $crate::ConstCStr
163		{
164			rustValue: $strval,
165			cValue: concat!($strval, "\0")
166		}
167    );
168    ($($strname:ident = $strval:expr);+;) => (
169        $(
170            const $strname: $crate::ConstCStr = const_cstr!($strval);
171        )+
172    );
173    ($(pub $strname:ident = $strval:expr);+;) => (
174        $(
175            pub const $strname: $crate::ConstCStr = const_cstr!($strval);
176        )+
177    );
178}
179
180#[test]
181fn test_creates_valid_str() {
182    const_cstr! {
183        HELLO_CSTR = "Hello, world!";
184    }
185
186    let cstr = unsafe { CStr::from_ptr(HELLO_CSTR.as_ptr()) };
187
188    assert_eq!(HELLO_CSTR.to_str(), cstr.to_str().unwrap());
189}
190