├── .gitignore ├── .travis.yml ├── Cargo.toml ├── LICENSE-APACHE ├── LICENSE-MIT ├── README.md └── src └── lib.rs /.gitignore: -------------------------------------------------------------------------------- 1 | /target/ 2 | **/*.rs.bk 3 | Cargo.lock 4 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: rust 2 | sudo: false 3 | 4 | rust: 5 | - nightly 6 | - beta 7 | - stable 8 | - 1.42.0 9 | 10 | script: 11 | - cargo build 12 | - cargo build --features alloc 13 | - cargo test --features alloc 14 | - cargo build --features std 15 | - cargo build --no-default-features 16 | - cargo build --no-default-features --features alloc 17 | - cargo build --no-default-features --features use_libc 18 | - cargo doc --no-deps 19 | 20 | notifications: 21 | email: false 22 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "cstr_core" 3 | version = "0.2.6" 4 | authors = ["Amanieu d'Antras "] 5 | description = "Implementation of CStr and CString for no_std environments." 6 | documentation = "https://docs.rs/cstr_core/" 7 | license = "Apache-2.0/MIT" 8 | repository = "https://github.com/Amanieu/cstr_core" 9 | readme = "README.md" 10 | keywords = ["cstr", "cstring", "no_std", "string", "c"] 11 | categories = ["data-structures", "no-std"] 12 | edition = "2018" 13 | 14 | [dependencies] 15 | cty = "0.2.1" 16 | memchr = { version = "2.3.3", default-features = false } 17 | 18 | [features] 19 | default = ["arc", "alloc"] 20 | alloc = [] 21 | std = [] 22 | arc = [] 23 | nightly = [] 24 | use_libc = ["memchr/libc"] 25 | -------------------------------------------------------------------------------- /LICENSE-APACHE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /LICENSE-MIT: -------------------------------------------------------------------------------- 1 | Copyright (c) 2016 The Rust Project Developers 2 | 3 | Permission is hereby granted, free of charge, to any 4 | person obtaining a copy of this software and associated 5 | documentation files (the "Software"), to deal in the 6 | Software without restriction, including without 7 | limitation the rights to use, copy, modify, merge, 8 | publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software 10 | is furnished to do so, subject to the following 11 | conditions: 12 | 13 | The above copyright notice and this permission notice 14 | shall be included in all copies or substantial portions 15 | of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF 18 | ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED 19 | TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 20 | PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT 21 | SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 22 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 23 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR 24 | IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 25 | DEALINGS IN THE SOFTWARE. 26 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | cstr_core 2 | ========= 3 | 4 | [![Build Status](https://travis-ci.org/Amanieu/cstr_core.svg?branch=master)](https://travis-ci.org/Amanieu/cstr_core) [![Crates.io](https://img.shields.io/crates/v/cstr_core.svg)](https://crates.io/crates/cstr_core) 5 | 6 | This crate provides implementations of `CStr` and `CString` which do not depend on the standard library and are suitable for `no_std` environments. 7 | 8 | `CString` support is only available if the `alloc` feature is enabled, which requires the `alloc` crate. 9 | `CStr` is always available. 10 | 11 | Some hardware targets (e.g. thumbv6m-none-eabi for Cortex M0,M0+) have no support for atomic operations. For these platforms, disable the `arc` feature to omit the parts of the crate that depend on atomic operations. Compatibility with thread-safe code and `Arc` will not be available. 12 | 13 | In addition, the `nightly` feature allows the usage of `CStr::from_bytes_with_nul_unchecked` to be used in a `const` context. However, it requires a nightly version of the compiler. 14 | 15 | ### Documentation 16 | 17 | [https://docs.rs/cstr_core](https://docs.rs/cstr_core) 18 | 19 | ## License 20 | 21 | Licensed under either of 22 | 23 | * Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0) 24 | * MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT) 25 | 26 | at your option. 27 | 28 | ### Contribution 29 | 30 | Unless you explicitly state otherwise, any contribution intentionally submitted 31 | for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any 32 | additional terms or conditions. 33 | -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | #![cfg_attr(not(feature = "std"), no_std)] 2 | #![warn(rust_2018_idioms)] 3 | #![cfg_attr(feature = "nightly", feature(const_raw_ptr_deref))] 4 | #![cfg_attr(feature = "nightly", feature(const_slice_from_raw_parts))] 5 | #![cfg_attr(feature = "nightly", feature(const_str_from_utf8))] 6 | #![cfg_attr(feature = "nightly", feature(const_eval_select))] 7 | #![cfg_attr(feature = "nightly", feature(core_intrinsics))] 8 | 9 | #[cfg(test)] 10 | extern crate std; 11 | 12 | #[cfg(feature = "alloc")] 13 | extern crate alloc; 14 | 15 | #[cfg(feature = "alloc")] 16 | use alloc::borrow::{Borrow, Cow, ToOwned}; 17 | #[cfg(feature = "alloc")] 18 | use alloc::boxed::Box; 19 | #[cfg(feature = "alloc")] 20 | use alloc::rc::Rc; 21 | #[cfg(feature = "alloc")] 22 | use alloc::string::String; 23 | #[cfg(feature = "alloc")] 24 | #[cfg(feature = "arc")] 25 | use alloc::sync::Arc; 26 | #[cfg(feature = "alloc")] 27 | use alloc::vec::Vec; 28 | #[cfg(feature = "alloc")] 29 | use core::{mem, ops, ptr}; 30 | 31 | use core::ascii; 32 | use core::cmp::Ordering; 33 | use core::fmt::{self, Write}; 34 | use core::slice; 35 | use core::str::{self, Utf8Error}; 36 | 37 | /// Re-export c_char 38 | pub use cty::c_char; 39 | 40 | #[inline] 41 | unsafe fn strlen(p: *const c_char) -> usize { 42 | let mut n = 0; 43 | while *p.offset(n as isize) != 0 { 44 | n += 1; 45 | } 46 | n 47 | } 48 | 49 | /// A drop-in implementation of `memchr` that is const. 50 | /// 51 | /// This is expected to perform way worse than any version the `memchr` crate provides. 52 | #[cfg(feature = "nightly")] 53 | const fn memchr_const(needle: u8, haystack: &[u8]) -> Option { 54 | let mut i = 0; 55 | loop { 56 | i += 1; 57 | if haystack.len() == i { 58 | return None; 59 | } 60 | if haystack[i] == needle { 61 | return Some(i); 62 | } 63 | } 64 | } 65 | 66 | /// Wrapper around memchr that is const, but still fast at runtime by dispatching through 67 | /// const_eval_select. 68 | #[inline] 69 | #[cfg(feature = "nightly")] 70 | const fn memchr(needle: u8, haystack: &[u8]) -> Option { 71 | // unsafe: Both versions provide the same functionality 72 | unsafe { core::intrinsics::const_eval_select((needle, haystack), memchr_const, memchr::memchr) } 73 | } 74 | 75 | #[cfg(not(feature = "nightly"))] 76 | use memchr::memchr; 77 | 78 | /// A type representing an owned, C-compatible, nul-terminated string with no nul bytes in the 79 | /// middle. 80 | /// 81 | /// This type serves the purpose of being able to safely generate a 82 | /// C-compatible string from a Rust byte slice or vector. An instance of this 83 | /// type is a static guarantee that the underlying bytes contain no interior 0 84 | /// bytes ("nul characters") and that the final byte is 0 ("nul terminator"). 85 | /// 86 | /// `CString` is to [`&CStr`] as [`String`] is to [`&str`]: the former 87 | /// in each pair are owned strings; the latter are borrowed 88 | /// references. 89 | /// 90 | /// # Creating a `CString` 91 | /// 92 | /// A `CString` is created from either a byte slice or a byte vector, 93 | /// or anything that implements [`Into`]`<`[`Vec`]`<`[`u8`]`>>` (for 94 | /// example, you can build a `CString` straight out of a [`String`] or 95 | /// a [`&str`], since both implement that trait). 96 | /// 97 | /// The [`new`] method will actually check that the provided `&[u8]` 98 | /// does not have 0 bytes in the middle, and return an error if it 99 | /// finds one. 100 | /// 101 | /// # Extracting a raw pointer to the whole C string 102 | /// 103 | /// `CString` implements a [`as_ptr`] method through the [`Deref`] 104 | /// trait. This method will give you a `*const c_char` which you can 105 | /// feed directly to extern functions that expect a nul-terminated 106 | /// string, like C's `strdup()`. Notice that [`as_ptr`] returns a 107 | /// read-only pointer; if the C code writes to it, that causes 108 | /// undefined behavior. 109 | /// 110 | /// # Extracting a slice of the whole C string 111 | /// 112 | /// Alternatively, you can obtain a `&[`[`u8`]`]` slice from a 113 | /// `CString` with the [`as_bytes`] method. Slices produced in this 114 | /// way do *not* contain the trailing nul terminator. This is useful 115 | /// when you will be calling an extern function that takes a `*const 116 | /// u8` argument which is not necessarily nul-terminated, plus another 117 | /// argument with the length of the string — like C's `strndup()`. 118 | /// You can of course get the slice's length with its 119 | /// [`len`][slice.len] method. 120 | /// 121 | /// If you need a `&[`[`u8`]`]` slice *with* the nul terminator, you 122 | /// can use [`as_bytes_with_nul`] instead. 123 | /// 124 | /// Once you have the kind of slice you need (with or without a nul 125 | /// terminator), you can call the slice's own 126 | /// [`as_ptr`][slice.as_ptr] method to get a read-only raw pointer to pass to 127 | /// extern functions. See the documentation for that function for a 128 | /// discussion on ensuring the lifetime of the raw pointer. 129 | /// 130 | /// [`new`]: #method.new 131 | /// [`as_bytes`]: #method.as_bytes 132 | /// [`as_bytes_with_nul`]: #method.as_bytes_with_nul 133 | /// [`as_ptr`]: #method.as_ptr 134 | /// [slice.len]: ../primitive.slice.html#method.len 135 | /// [`Deref`]: core::ops::Deref 136 | /// [`CStr`]: struct.CStr.html 137 | /// [`&CStr`]: struct.CStr.html 138 | /// 139 | /// # Examples 140 | /// 141 | /// ```ignore (extern-declaration) 142 | /// # fn main() { 143 | /// use cstr_core::CString; 144 | /// use cstr_core::c_char; 145 | /// 146 | /// extern { 147 | /// fn my_printer(s: *const c_char); 148 | /// } 149 | /// 150 | /// // We are certain that our string doesn't have 0 bytes in the middle, 151 | /// // so we can .expect() 152 | /// let c_to_print = CString::new("Hello, world!").expect("CString::new failed"); 153 | /// unsafe { 154 | /// my_printer(c_to_print.as_ptr()); 155 | /// } 156 | /// # } 157 | /// ``` 158 | /// 159 | /// # Safety 160 | /// 161 | /// `CString` is intended for working with traditional C-style strings 162 | /// (a sequence of non-nul bytes terminated by a single nul byte); the 163 | /// primary use case for these kinds of strings is interoperating with C-like 164 | /// code. Often you will need to transfer ownership to/from that external 165 | /// code. It is strongly recommended that you thoroughly read through the 166 | /// documentation of `CString` before use, as improper ownership management 167 | /// of `CString` instances can lead to invalid memory accesses, memory leaks, 168 | /// and other memory errors. 169 | 170 | #[cfg(feature = "alloc")] 171 | #[derive(PartialEq, PartialOrd, Eq, Ord, Hash, Clone)] 172 | pub struct CString { 173 | // Invariant 1: the slice ends with a zero byte and has a length of at least one. 174 | // Invariant 2: the slice contains only one zero byte. 175 | // Improper usage of unsafe function can break Invariant 2, but not Invariant 1. 176 | inner: Box<[u8]>, 177 | } 178 | 179 | /// Representation of a borrowed C string. 180 | /// 181 | /// This type represents a borrowed reference to a nul-terminated 182 | /// array of bytes. It can be constructed safely from a `&[`[`u8`]`]` 183 | /// slice, or unsafely from a raw `*const c_char`. It can then be 184 | /// converted to a Rust [`&str`] by performing UTF-8 validation, or 185 | /// into an owned [`CString`]. 186 | /// 187 | /// `&CStr` is to [`CString`] as [`&str`] is to [`String`]: the former 188 | /// in each pair are borrowed references; the latter are owned 189 | /// strings. 190 | /// 191 | /// Note that this structure is **not** `repr(C)` and is not recommended to be 192 | /// placed in the signatures of FFI functions. Instead, safe wrappers of FFI 193 | /// functions may leverage the unsafe [`from_ptr`] constructor to provide a safe 194 | /// interface to other consumers. 195 | /// 196 | /// # Examples 197 | /// 198 | /// Inspecting a foreign C string: 199 | /// 200 | /// ```ignore (extern-declaration) 201 | /// use cstr_core::CStr; 202 | /// use cstr_core::c_char; 203 | /// 204 | /// extern { fn my_string() -> *const c_char; } 205 | /// 206 | /// unsafe { 207 | /// let slice = CStr::from_ptr(my_string()); 208 | /// println!("string buffer size without nul terminator: {}", slice.to_bytes().len()); 209 | /// } 210 | /// ``` 211 | /// 212 | /// Passing a Rust-originating C string: 213 | /// 214 | /// ```ignore (extern-declaration) 215 | /// use cstr_core::{CString, CStr}; 216 | /// use cstr_core::c_char; 217 | /// 218 | /// fn work(data: &CStr) { 219 | /// extern { fn work_with(data: *const c_char); } 220 | /// 221 | /// unsafe { work_with(data.as_ptr()) } 222 | /// } 223 | /// 224 | /// let s = CString::new("data data data data").expect("CString::new failed"); 225 | /// work(&s); 226 | /// ``` 227 | /// 228 | /// Converting a foreign C string into a Rust [`String`]: 229 | /// 230 | /// ```ignore (extern-declaration) 231 | /// use cstr_core::CStr; 232 | /// use cstr_core::c_char; 233 | /// 234 | /// extern { fn my_string() -> *const c_char; } 235 | /// 236 | /// fn my_string_safe() -> String { 237 | /// unsafe { 238 | /// CStr::from_ptr(my_string()).to_string_lossy().into_owned() 239 | /// } 240 | /// } 241 | /// 242 | /// println!("string: {}", my_string_safe()); 243 | /// ``` 244 | /// 245 | /// [`CString`]: struct.CString.html 246 | /// [`String`]: https://doc.rust-lang.org/std/string/struct.String.html 247 | /// [`from_ptr`]: #method.from_ptr 248 | #[derive(Hash)] 249 | // FIXME: 250 | // `fn from` in `impl From<&CStr> for Box` current implementation relies 251 | // on `CStr` being layout-compatible with `[u8]`. 252 | // When attribute privacy is implemented, `CStr` should be annotated as `#[repr(transparent)]`. 253 | // Anyway, `CStr` representation and layout are considered implementation detail, are 254 | // not documented and must not be relied upon. 255 | pub struct CStr { 256 | // FIXME: this should not be represented with a DST slice but rather with 257 | // just a raw `c_char` along with some form of marker to make 258 | // this an unsized type. Essentially `sizeof(&CStr)` should be the 259 | // same as `sizeof(&c_char)` but `CStr` should be an unsized type. 260 | inner: [c_char], 261 | } 262 | 263 | /// An error indicating that an interior nul byte was found. 264 | /// 265 | /// While Rust strings may contain nul bytes in the middle, C strings 266 | /// can't, as that byte would effectively truncate the string. 267 | /// 268 | /// This error is created by the [`new`][`CString::new`] method on 269 | /// [`CString`]. See its documentation for more. 270 | /// 271 | /// [`CString`]: struct.CString.html 272 | /// [`CString::new`]: struct.CString.html#method.new 273 | /// 274 | /// # Examples 275 | /// 276 | /// ``` 277 | /// use cstr_core::{CString, NulError}; 278 | /// 279 | /// let _: NulError = CString::new(b"f\0oo".to_vec()).unwrap_err(); 280 | /// ``` 281 | #[cfg(feature = "alloc")] 282 | #[derive(Clone, PartialEq, Eq, Debug)] 283 | pub struct NulError(usize, Vec); 284 | 285 | /// An error indicating that a nul byte was not in the expected position. 286 | /// 287 | /// The slice used to create a [`CStr`] must have one and only one nul 288 | /// byte at the end of the slice. 289 | /// 290 | /// This error is created by the 291 | /// [`from_bytes_with_nul`][`CStr::from_bytes_with_nul`] method on 292 | /// [`CStr`]. See its documentation for more. 293 | /// 294 | /// [`CStr`]: struct.CStr.html 295 | /// [`CStr::from_bytes_with_nul`]: struct.CStr.html#method.from_bytes_with_nul 296 | /// 297 | /// # Examples 298 | /// 299 | /// ``` 300 | /// use cstr_core::{CStr, FromBytesWithNulError}; 301 | /// 302 | /// let _: FromBytesWithNulError = CStr::from_bytes_with_nul(b"f\0oo").unwrap_err(); 303 | /// ``` 304 | #[derive(Clone, PartialEq, Eq, Debug)] 305 | pub struct FromBytesWithNulError { 306 | kind: FromBytesWithNulErrorKind, 307 | } 308 | 309 | #[derive(Clone, PartialEq, Eq, Debug)] 310 | enum FromBytesWithNulErrorKind { 311 | InteriorNul(usize), 312 | NotNulTerminated, 313 | } 314 | 315 | impl FromBytesWithNulError { 316 | const fn interior_nul(pos: usize) -> FromBytesWithNulError { 317 | FromBytesWithNulError { 318 | kind: FromBytesWithNulErrorKind::InteriorNul(pos), 319 | } 320 | } 321 | const fn not_nul_terminated() -> FromBytesWithNulError { 322 | FromBytesWithNulError { 323 | kind: FromBytesWithNulErrorKind::NotNulTerminated, 324 | } 325 | } 326 | } 327 | 328 | /// An error indicating invalid UTF-8 when converting a [`CString`] into a [`String`]. 329 | /// 330 | /// `CString` is just a wrapper over a buffer of bytes with a nul 331 | /// terminator; [`into_string`][`CString::into_string`] performs UTF-8 332 | /// validation on those bytes and may return this error. 333 | /// 334 | /// This `struct` is created by the 335 | /// [`into_string`][`CString::into_string`] method on [`CString`]. See 336 | /// its documentation for more. 337 | /// 338 | /// [`CString`]: struct.CString.html 339 | /// [`CString::into_string`]: struct.CString.html#method.into_string 340 | #[cfg(feature = "alloc")] 341 | #[derive(Clone, PartialEq, Eq, Debug)] 342 | pub struct IntoStringError { 343 | inner: CString, 344 | error: Utf8Error, 345 | } 346 | 347 | #[cfg(feature = "alloc")] 348 | impl CString { 349 | /// Creates a new C-compatible string from a container of bytes. 350 | /// 351 | /// This function will consume the provided data and use the 352 | /// underlying bytes to construct a new string, ensuring that 353 | /// there is a trailing 0 byte. This trailing 0 byte will be 354 | /// appended by this function; the provided data should *not* 355 | /// contain any 0 bytes in it. 356 | /// 357 | /// # Examples 358 | /// 359 | /// ```ignore (extern-declaration) 360 | /// use cstr_core::CString; 361 | /// use cstr_core::c_char; 362 | /// 363 | /// extern { fn puts(s: *const c_char); } 364 | /// 365 | /// let to_print = CString::new("Hello!").expect("CString::new failed"); 366 | /// unsafe { 367 | /// puts(to_print.as_ptr()); 368 | /// } 369 | /// ``` 370 | /// 371 | /// # Errors 372 | /// 373 | /// This function will return an error if the supplied bytes contain an 374 | /// internal 0 byte. The [`NulError`] returned will contain the bytes as well as 375 | /// the position of the nul byte. 376 | /// 377 | /// [`NulError`]: struct.NulError.html 378 | pub fn new>>(t: T) -> Result { 379 | Self::_new(t.into()) 380 | } 381 | 382 | fn _new(bytes: Vec) -> Result { 383 | match memchr::memchr(0, &bytes) { 384 | Some(i) => Err(NulError(i, bytes)), 385 | None => Ok(unsafe { CString::from_vec_unchecked(bytes) }), 386 | } 387 | } 388 | 389 | /// Creates a C-compatible string from a byte vector without checking for 390 | /// interior 0 bytes. 391 | /// 392 | /// This method is equivalent to [`new`] except that no runtime assertion 393 | /// is made that `v` contains no 0 bytes, and it requires an actual 394 | /// byte vector, not anything that can be converted to one with Into. 395 | /// 396 | /// [`new`]: #method.new 397 | /// 398 | /// # Examples 399 | /// 400 | /// ``` 401 | /// use cstr_core::CString; 402 | /// 403 | /// let raw = b"foo".to_vec(); 404 | /// unsafe { 405 | /// let c_string = CString::from_vec_unchecked(raw); 406 | /// } 407 | /// ``` 408 | pub unsafe fn from_vec_unchecked(mut v: Vec) -> CString { 409 | v.reserve_exact(1); 410 | v.push(0); 411 | CString { 412 | inner: v.into_boxed_slice(), 413 | } 414 | } 415 | 416 | /// Retakes ownership of a `CString` that was transferred to C via [`into_raw`]. 417 | /// 418 | /// Additionally, the length of the string will be recalculated from the pointer. 419 | /// 420 | /// # Safety 421 | /// 422 | /// This should only ever be called with a pointer that was earlier 423 | /// obtained by calling [`into_raw`] on a `CString`. Other usage (e.g., trying to take 424 | /// ownership of a string that was allocated by foreign code) is likely to lead 425 | /// to undefined behavior or allocator corruption. 426 | /// 427 | /// > **Note:** If you need to borrow a string that was allocated by 428 | /// > foreign code, use [`CStr`]. If you need to take ownership of 429 | /// > a string that was allocated by foreign code, you will need to 430 | /// > make your own provisions for freeing it appropriately, likely 431 | /// > with the foreign code's API to do that. 432 | /// 433 | /// [`into_raw`]: #method.into_raw 434 | /// [`CStr`]: struct.CStr.html 435 | /// 436 | /// # Examples 437 | /// 438 | /// Creates a `CString`, pass ownership to an `extern` function (via raw pointer), then retake 439 | /// ownership with `from_raw`: 440 | /// 441 | /// ```ignore (extern-declaration) 442 | /// use cstr_core::CString; 443 | /// use cstr_core::c_char; 444 | /// 445 | /// extern { 446 | /// fn some_extern_function(s: *mut c_char); 447 | /// } 448 | /// 449 | /// let c_string = CString::new("Hello!").expect("CString::new failed"); 450 | /// let raw = c_string.into_raw(); 451 | /// unsafe { 452 | /// some_extern_function(raw); 453 | /// let c_string = CString::from_raw(raw); 454 | /// } 455 | /// ``` 456 | pub unsafe fn from_raw(ptr: *mut c_char) -> CString { 457 | let len = strlen(ptr) + 1; // Including the NUL byte 458 | let slice = slice::from_raw_parts_mut(ptr, len as usize); 459 | CString { 460 | inner: Box::from_raw(slice as *mut [c_char] as *mut [u8]), 461 | } 462 | } 463 | 464 | /// Consumes the `CString` and transfers ownership of the string to a C caller. 465 | /// 466 | /// The pointer which this function returns must be returned to Rust and reconstituted using 467 | /// [`from_raw`] to be properly deallocated. Specifically, one 468 | /// should *not* use the standard C `free()` function to deallocate 469 | /// this string. 470 | /// 471 | /// Failure to call [`from_raw`] will lead to a memory leak. 472 | /// 473 | /// [`from_raw`]: #method.from_raw 474 | /// 475 | /// # Examples 476 | /// 477 | /// ``` 478 | /// use cstr_core::CString; 479 | /// 480 | /// let c_string = CString::new("foo").expect("CString::new failed"); 481 | /// 482 | /// let ptr = c_string.into_raw(); 483 | /// 484 | /// unsafe { 485 | /// assert_eq!(b'f', *ptr as u8); 486 | /// assert_eq!(b'o', *ptr.offset(1) as u8); 487 | /// assert_eq!(b'o', *ptr.offset(2) as u8); 488 | /// assert_eq!(b'\0', *ptr.offset(3) as u8); 489 | /// 490 | /// // retake pointer to free memory 491 | /// let _ = CString::from_raw(ptr); 492 | /// } 493 | /// ``` 494 | #[inline] 495 | pub fn into_raw(self) -> *mut c_char { 496 | Box::into_raw(self.into_inner()) as *mut c_char 497 | } 498 | /// Converts the `CString` into a [`String`] if it contains valid UTF-8 data. 499 | /// 500 | /// On failure, ownership of the original `CString` is returned. 501 | /// 502 | /// # Examples 503 | /// 504 | /// ``` 505 | /// use cstr_core::CString; 506 | /// 507 | /// let valid_utf8 = vec![b'f', b'o', b'o']; 508 | /// let cstring = CString::new(valid_utf8).expect("CString::new failed"); 509 | /// assert_eq!(cstring.into_string().expect("into_string() call failed"), "foo"); 510 | /// 511 | /// let invalid_utf8 = vec![b'f', 0xff, b'o', b'o']; 512 | /// let cstring = CString::new(invalid_utf8).expect("CString::new failed"); 513 | /// let err = cstring.into_string().err().expect("into_string().err() failed"); 514 | /// assert_eq!(err.utf8_error().valid_up_to(), 1); 515 | /// ``` 516 | pub fn into_string(self) -> Result { 517 | String::from_utf8(self.into_bytes()).map_err(|e| IntoStringError { 518 | error: e.utf8_error(), 519 | inner: unsafe { CString::from_vec_unchecked(e.into_bytes()) }, 520 | }) 521 | } 522 | 523 | /// Consumes the `CString` and returns the underlying byte buffer. 524 | /// 525 | /// The returned buffer does **not** contain the trailing nul 526 | /// terminator, and it is guaranteed to not have any interior nul 527 | /// bytes. 528 | /// 529 | /// # Examples 530 | /// 531 | /// ``` 532 | /// use cstr_core::CString; 533 | /// 534 | /// let c_string = CString::new("foo").expect("CString::new failed"); 535 | /// let bytes = c_string.into_bytes(); 536 | /// assert_eq!(bytes, vec![b'f', b'o', b'o']); 537 | /// ``` 538 | pub fn into_bytes(self) -> Vec { 539 | let mut vec = self.into_inner().into_vec(); 540 | let _nul = vec.pop(); 541 | debug_assert_eq!(_nul, Some(0u8)); 542 | vec 543 | } 544 | 545 | /// Equivalent to the [`into_bytes`] function except that the returned vector 546 | /// includes the trailing nul terminator. 547 | /// 548 | /// [`into_bytes`]: #method.into_bytes 549 | /// 550 | /// # Examples 551 | /// 552 | /// ``` 553 | /// use cstr_core::CString; 554 | /// 555 | /// let c_string = CString::new("foo").expect("CString::new failed"); 556 | /// let bytes = c_string.into_bytes_with_nul(); 557 | /// assert_eq!(bytes, vec![b'f', b'o', b'o', b'\0']); 558 | /// ``` 559 | pub fn into_bytes_with_nul(self) -> Vec { 560 | self.into_inner().into_vec() 561 | } 562 | 563 | /// Returns the contents of this `CString` as a slice of bytes. 564 | /// 565 | /// The returned slice does **not** contain the trailing nul 566 | /// terminator, and it is guaranteed to not have any interior nul 567 | /// bytes. If you need the nul terminator, use 568 | /// [`as_bytes_with_nul`] instead. 569 | /// 570 | /// [`as_bytes_with_nul`]: #method.as_bytes_with_nul 571 | /// 572 | /// # Examples 573 | /// 574 | /// ``` 575 | /// use cstr_core::CString; 576 | /// 577 | /// let c_string = CString::new("foo").expect("CString::new failed"); 578 | /// let bytes = c_string.as_bytes(); 579 | /// assert_eq!(bytes, &[b'f', b'o', b'o']); 580 | /// ``` 581 | #[inline] 582 | pub fn as_bytes(&self) -> &[u8] { 583 | &self.inner[..self.inner.len() - 1] 584 | } 585 | 586 | /// Equivalent to the [`as_bytes`] function except that the returned slice 587 | /// includes the trailing nul terminator. 588 | /// 589 | /// [`as_bytes`]: #method.as_bytes 590 | /// 591 | /// # Examples 592 | /// 593 | /// ``` 594 | /// use cstr_core::CString; 595 | /// 596 | /// let c_string = CString::new("foo").expect("CString::new failed"); 597 | /// let bytes = c_string.as_bytes_with_nul(); 598 | /// assert_eq!(bytes, &[b'f', b'o', b'o', b'\0']); 599 | /// ``` 600 | #[inline] 601 | pub fn as_bytes_with_nul(&self) -> &[u8] { 602 | &self.inner 603 | } 604 | 605 | /// Extracts a [`CStr`] slice containing the entire string. 606 | /// 607 | /// [`CStr`]: struct.CStr.html 608 | /// 609 | /// # Examples 610 | /// 611 | /// ``` 612 | /// use cstr_core::{CString, CStr}; 613 | /// 614 | /// let c_string = CString::new(b"foo".to_vec()).expect("CString::new failed"); 615 | /// let cstr = c_string.as_c_str(); 616 | /// assert_eq!(cstr, 617 | /// CStr::from_bytes_with_nul(b"foo\0").expect("CStr::from_bytes_with_nul failed")); 618 | /// ``` 619 | #[inline] 620 | pub fn as_c_str(&self) -> &CStr { 621 | &*self 622 | } 623 | 624 | /// Converts this `CString` into a boxed [`CStr`]. 625 | /// 626 | /// [`CStr`]: struct.CStr.html 627 | /// 628 | /// # Examples 629 | /// 630 | /// ``` 631 | /// use cstr_core::{CString, CStr}; 632 | /// 633 | /// let c_string = CString::new(b"foo".to_vec()).expect("CString::new failed"); 634 | /// let boxed = c_string.into_boxed_c_str(); 635 | /// assert_eq!(&*boxed, 636 | /// CStr::from_bytes_with_nul(b"foo\0").expect("CStr::from_bytes_with_nul failed")); 637 | /// ``` 638 | pub fn into_boxed_c_str(self) -> Box { 639 | unsafe { Box::from_raw(Box::into_raw(self.into_inner()) as *mut CStr) } 640 | } 641 | 642 | /// Bypass "move out of struct which implements [`Drop`] trait" restriction. 643 | fn into_inner(self) -> Box<[u8]> { 644 | // Rationale: `mem::forget(self)` invalidates the previous call to `ptr::read(&self.inner)` 645 | // so we use `ManuallyDrop` to ensure `self` is not dropped. 646 | // Then we can return the box directly without invalidating it. 647 | // See https://github.com/rust-lang/rust/issues/62553. 648 | let this = mem::ManuallyDrop::new(self); 649 | unsafe { ptr::read(&this.inner) } 650 | } 651 | } 652 | 653 | // Turns this `CString` into an empty string to prevent 654 | // memory unsafe code from working by accident. Inline 655 | // to prevent LLVM from optimizing it away in debug builds. 656 | #[cfg(feature = "alloc")] 657 | impl Drop for CString { 658 | #[inline] 659 | fn drop(&mut self) { 660 | unsafe { 661 | *self.inner.get_unchecked_mut(0) = 0; 662 | } 663 | } 664 | } 665 | 666 | #[cfg(feature = "alloc")] 667 | impl ops::Deref for CString { 668 | type Target = CStr; 669 | 670 | #[inline] 671 | fn deref(&self) -> &CStr { 672 | unsafe { CStr::from_bytes_with_nul_unchecked(self.as_bytes_with_nul()) } 673 | } 674 | } 675 | 676 | #[cfg(feature = "alloc")] 677 | impl fmt::Debug for CString { 678 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 679 | fmt::Debug::fmt(&**self, f) 680 | } 681 | } 682 | 683 | #[cfg(feature = "alloc")] 684 | impl From for Vec { 685 | /// Converts a [`CString`] into a [`Vec`]``. 686 | /// 687 | /// The conversion consumes the [`CString`], and removes the terminating NUL byte. 688 | #[inline] 689 | fn from(s: CString) -> Vec { 690 | s.into_bytes() 691 | } 692 | } 693 | 694 | impl fmt::Debug for CStr { 695 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 696 | write!(f, "\"")?; 697 | for byte in self 698 | .to_bytes() 699 | .iter() 700 | .flat_map(|&b| ascii::escape_default(b)) 701 | { 702 | f.write_char(byte as char)?; 703 | } 704 | write!(f, "\"") 705 | } 706 | } 707 | 708 | impl<'a> Default for &'a CStr { 709 | fn default() -> &'a CStr { 710 | const SLICE: &[c_char] = &[0]; 711 | unsafe { CStr::from_ptr(SLICE.as_ptr()) } 712 | } 713 | } 714 | 715 | #[cfg(feature = "alloc")] 716 | impl Default for CString { 717 | /// Creates an empty `CString`. 718 | fn default() -> CString { 719 | let a: &CStr = Default::default(); 720 | a.to_owned() 721 | } 722 | } 723 | 724 | #[cfg(feature = "alloc")] 725 | impl Borrow for CString { 726 | #[inline] 727 | fn borrow(&self) -> &CStr { 728 | self 729 | } 730 | } 731 | 732 | #[cfg(feature = "alloc")] 733 | impl<'a> From> for CString { 734 | #[inline] 735 | fn from(s: Cow<'a, CStr>) -> Self { 736 | s.into_owned() 737 | } 738 | } 739 | 740 | #[cfg(feature = "alloc")] 741 | impl From<&CStr> for Box { 742 | fn from(s: &CStr) -> Box { 743 | let boxed: Box<[u8]> = Box::from(s.to_bytes_with_nul()); 744 | unsafe { Box::from_raw(Box::into_raw(boxed) as *mut CStr) } 745 | } 746 | } 747 | 748 | #[cfg(feature = "alloc")] 749 | impl From> for CString { 750 | /// Converts a [`Box`]`` into a [`CString`] without copying or allocating. 751 | #[inline] 752 | fn from(s: Box) -> CString { 753 | s.into_c_string() 754 | } 755 | } 756 | 757 | #[cfg(feature = "alloc")] 758 | impl Clone for Box { 759 | #[inline] 760 | fn clone(&self) -> Self { 761 | (**self).into() 762 | } 763 | } 764 | 765 | #[cfg(feature = "alloc")] 766 | impl From for Box { 767 | /// Converts a [`CString`] into a [`Box`]`` without copying or allocating. 768 | #[inline] 769 | fn from(s: CString) -> Box { 770 | s.into_boxed_c_str() 771 | } 772 | } 773 | 774 | #[cfg(feature = "alloc")] 775 | impl<'a> From for Cow<'a, CStr> { 776 | #[inline] 777 | fn from(s: CString) -> Cow<'a, CStr> { 778 | Cow::Owned(s) 779 | } 780 | } 781 | 782 | #[cfg(feature = "alloc")] 783 | impl<'a> From<&'a CStr> for Cow<'a, CStr> { 784 | #[inline] 785 | fn from(s: &'a CStr) -> Cow<'a, CStr> { 786 | Cow::Borrowed(s) 787 | } 788 | } 789 | 790 | #[cfg(feature = "alloc")] 791 | impl<'a> From<&'a CString> for Cow<'a, CStr> { 792 | #[inline] 793 | fn from(s: &'a CString) -> Cow<'a, CStr> { 794 | Cow::Borrowed(s.as_c_str()) 795 | } 796 | } 797 | 798 | #[cfg(feature = "alloc")] 799 | #[cfg(feature = "arc")] 800 | impl From for Arc { 801 | #[inline] 802 | fn from(s: CString) -> Arc { 803 | let arc: Arc<[u8]> = Arc::from(s.into_inner()); 804 | unsafe { Arc::from_raw(Arc::into_raw(arc) as *const CStr) } 805 | } 806 | } 807 | 808 | #[cfg(feature = "alloc")] 809 | #[cfg(feature = "arc")] 810 | impl<'a> From<&'a CStr> for Arc { 811 | #[inline] 812 | fn from(s: &CStr) -> Arc { 813 | let arc: Arc<[u8]> = Arc::from(s.to_bytes_with_nul()); 814 | unsafe { Arc::from_raw(Arc::into_raw(arc) as *const CStr) } 815 | } 816 | } 817 | 818 | #[cfg(feature = "alloc")] 819 | impl From for Rc { 820 | #[inline] 821 | fn from(s: CString) -> Rc { 822 | let rc: Rc<[u8]> = Rc::from(s.into_inner()); 823 | unsafe { Rc::from_raw(Rc::into_raw(rc) as *const CStr) } 824 | } 825 | } 826 | 827 | #[cfg(feature = "alloc")] 828 | impl<'a> From<&'a CStr> for Rc { 829 | #[inline] 830 | fn from(s: &CStr) -> Rc { 831 | let rc: Rc<[u8]> = Rc::from(s.to_bytes_with_nul()); 832 | unsafe { Rc::from_raw(Rc::into_raw(rc) as *const CStr) } 833 | } 834 | } 835 | 836 | #[cfg(feature = "alloc")] 837 | impl Default for Box { 838 | fn default() -> Box { 839 | let boxed: Box<[u8]> = Box::from([0]); 840 | unsafe { Box::from_raw(Box::into_raw(boxed) as *mut CStr) } 841 | } 842 | } 843 | 844 | #[cfg(feature = "std")] 845 | use std::ffi::{CStr as StdCStr, CString as StdCString}; 846 | 847 | #[cfg(feature = "std")] 848 | impl From for StdCString { 849 | #[inline] 850 | fn from(s: CString) -> StdCString { 851 | unsafe { StdCString::from_vec_unchecked(s.into_bytes()) } 852 | } 853 | } 854 | 855 | #[cfg(feature = "std")] 856 | impl<'a> From<&'a CStr> for &'a StdCStr { 857 | #[inline] 858 | fn from(s: &'a CStr) -> &'a StdCStr { 859 | s.as_ref() 860 | } 861 | } 862 | 863 | #[cfg(feature = "std")] 864 | impl From for CString { 865 | #[inline] 866 | fn from(s: StdCString) -> CString { 867 | unsafe { CString::from_vec_unchecked(s.into_bytes()) } 868 | } 869 | } 870 | 871 | #[cfg(feature = "std")] 872 | impl<'a> From<&'a StdCStr> for &'a CStr { 873 | #[inline] 874 | fn from(s: &'a StdCStr) -> &'a CStr { 875 | unsafe { CStr::from_bytes_with_nul_unchecked(s.to_bytes_with_nul()) } 876 | } 877 | } 878 | 879 | #[cfg(feature = "std")] 880 | impl AsRef for CString { 881 | #[inline] 882 | fn as_ref(&self) -> &StdCStr { 883 | AsRef::::as_ref(self).as_ref() 884 | } 885 | } 886 | 887 | #[cfg(feature = "std")] 888 | impl Borrow for CString { 889 | #[inline] 890 | fn borrow(&self) -> &StdCStr { 891 | self.as_ref() 892 | } 893 | } 894 | 895 | #[cfg(feature = "std")] 896 | impl AsRef for CStr { 897 | #[inline] 898 | fn as_ref(&self) -> &StdCStr { 899 | unsafe { StdCStr::from_bytes_with_nul_unchecked(self.to_bytes_with_nul()) } 900 | } 901 | } 902 | 903 | #[cfg(feature = "alloc")] 904 | impl NulError { 905 | /// Returns the position of the nul byte in the slice that was provided to 906 | /// [`CString::new`]. 907 | /// 908 | /// [`CString::new`]: struct.CString.html#method.new 909 | /// 910 | /// # Examples 911 | /// 912 | /// ``` 913 | /// use cstr_core::CString; 914 | /// 915 | /// let nul_error = CString::new("foo\0bar").unwrap_err(); 916 | /// assert_eq!(nul_error.nul_position(), 3); 917 | /// 918 | /// let nul_error = CString::new("foo bar\0").unwrap_err(); 919 | /// assert_eq!(nul_error.nul_position(), 7); 920 | /// ``` 921 | pub fn nul_position(&self) -> usize { 922 | self.0 923 | } 924 | 925 | /// Consumes this error, returning the underlying vector of bytes which 926 | /// generated the error in the first place. 927 | /// 928 | /// # Examples 929 | /// 930 | /// ``` 931 | /// use cstr_core::CString; 932 | /// 933 | /// let nul_error = CString::new("foo\0bar").unwrap_err(); 934 | /// assert_eq!(nul_error.into_vec(), b"foo\0bar"); 935 | /// ``` 936 | pub fn into_vec(self) -> Vec { 937 | self.1 938 | } 939 | } 940 | 941 | #[cfg(feature = "alloc")] 942 | impl fmt::Display for NulError { 943 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 944 | write!(f, "nul byte found in provided data at position: {}", self.0) 945 | } 946 | } 947 | 948 | impl fmt::Display for FromBytesWithNulError { 949 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 950 | let description = match self.kind { 951 | FromBytesWithNulErrorKind::InteriorNul(..) => { 952 | "data provided contains an interior nul byte" 953 | } 954 | FromBytesWithNulErrorKind::NotNulTerminated => "data provided is not nul terminated", 955 | }; 956 | f.write_str(description)?; 957 | if let FromBytesWithNulErrorKind::InteriorNul(pos) = self.kind { 958 | write!(f, " at byte pos {}", pos)?; 959 | } 960 | Ok(()) 961 | } 962 | } 963 | 964 | #[cfg(feature = "alloc")] 965 | impl IntoStringError { 966 | /// Consumes this error, returning original [`CString`] which generated the 967 | /// error. 968 | /// 969 | /// [`CString`]: struct.CString.html 970 | pub fn into_cstring(self) -> CString { 971 | self.inner 972 | } 973 | 974 | /// Access the underlying UTF-8 error that was the cause of this error. 975 | pub fn utf8_error(&self) -> Utf8Error { 976 | self.error 977 | } 978 | } 979 | 980 | #[cfg(feature = "alloc")] 981 | impl fmt::Display for IntoStringError { 982 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 983 | "C string contained non-utf8 bytes".fmt(f) 984 | } 985 | } 986 | 987 | impl CStr { 988 | /// Wraps a raw C string with a safe C string wrapper. 989 | /// 990 | /// This function will wrap the provided `ptr` with a `CStr` wrapper, which 991 | /// allows inspection and interoperation of non-owned C strings. The total 992 | /// size of the raw C string must be smaller than `isize::MAX` **bytes** 993 | /// in memory due to calling the `slice::from_raw_parts` function. 994 | /// This method is unsafe for a number of reasons: 995 | /// 996 | /// * There is no guarantee to the validity of `ptr`. 997 | /// * The returned lifetime is not guaranteed to be the actual lifetime of 998 | /// `ptr`. 999 | /// * There is no guarantee that the memory pointed to by `ptr` contains a 1000 | /// valid nul terminator byte at the end of the string. 1001 | /// * It is not guaranteed that the memory pointed by `ptr` won't change 1002 | /// before the `CStr` has been destroyed. 1003 | /// 1004 | /// > **Note**: This operation is intended to be a 0-cost cast but it is 1005 | /// > currently implemented with an up-front calculation of the length of 1006 | /// > the string. This is not guaranteed to always be the case. 1007 | /// 1008 | /// # Examples 1009 | /// 1010 | /// ```ignore (extern-declaration) 1011 | /// # fn main() { 1012 | /// use cstr_core::CStr; 1013 | /// use cstr_core::c_char; 1014 | /// 1015 | /// extern { 1016 | /// fn my_string() -> *const c_char; 1017 | /// } 1018 | /// 1019 | /// unsafe { 1020 | /// let slice = CStr::from_ptr(my_string()); 1021 | /// println!("string returned: {}", slice.to_str().unwrap()); 1022 | /// } 1023 | /// # } 1024 | /// ``` 1025 | pub unsafe fn from_ptr<'a>(ptr: *const c_char) -> &'a CStr { 1026 | let len = strlen(ptr); 1027 | let ptr = ptr as *const u8; 1028 | CStr::from_bytes_with_nul_unchecked(slice::from_raw_parts(ptr, len as usize + 1)) 1029 | } 1030 | 1031 | /// Creates a C string wrapper from a byte slice. 1032 | /// 1033 | /// This function will cast the provided `bytes` to a `CStr` 1034 | /// wrapper after ensuring that the byte slice is nul-terminated 1035 | /// and does not contain any interior nul bytes. 1036 | /// 1037 | /// # Examples 1038 | /// 1039 | /// ``` 1040 | /// use cstr_core::CStr; 1041 | /// 1042 | /// let cstr = CStr::from_bytes_with_nul(b"hello\0"); 1043 | /// assert!(cstr.is_ok()); 1044 | /// ``` 1045 | /// 1046 | /// Creating a `CStr` without a trailing nul terminator is an error: 1047 | /// 1048 | /// ``` 1049 | /// use cstr_core::CStr; 1050 | /// 1051 | /// let cstr = CStr::from_bytes_with_nul(b"hello"); 1052 | /// assert!(cstr.is_err()); 1053 | /// ``` 1054 | /// 1055 | /// Creating a `CStr` with an interior nul byte is an error: 1056 | /// 1057 | /// ``` 1058 | /// use cstr_core::CStr; 1059 | /// 1060 | /// let cstr = CStr::from_bytes_with_nul(b"he\0llo\0"); 1061 | /// assert!(cstr.is_err()); 1062 | /// ``` 1063 | #[cfg(feature = "nightly")] 1064 | pub const fn from_bytes_with_nul(bytes: &[u8]) -> Result<&CStr, FromBytesWithNulError> { 1065 | let nul_pos = memchr(0, bytes); 1066 | if let Some(nul_pos) = nul_pos { 1067 | if nul_pos + 1 != bytes.len() { 1068 | return Err(FromBytesWithNulError::interior_nul(nul_pos)); 1069 | } 1070 | Ok(unsafe { CStr::from_bytes_with_nul_unchecked(bytes) }) 1071 | } else { 1072 | Err(FromBytesWithNulError::not_nul_terminated()) 1073 | } 1074 | } 1075 | 1076 | /// Creates a C string wrapper from a byte slice. 1077 | /// 1078 | /// This function will cast the provided `bytes` to a `CStr` 1079 | /// wrapper after ensuring that the byte slice is nul-terminated 1080 | /// and does not contain any interior nul bytes. 1081 | /// 1082 | /// # Examples 1083 | /// 1084 | /// ``` 1085 | /// use cstr_core::CStr; 1086 | /// 1087 | /// let cstr = CStr::from_bytes_with_nul(b"hello\0"); 1088 | /// assert!(cstr.is_ok()); 1089 | /// ``` 1090 | /// 1091 | /// Creating a `CStr` without a trailing nul terminator is an error: 1092 | /// 1093 | /// ``` 1094 | /// use cstr_core::CStr; 1095 | /// 1096 | /// let cstr = CStr::from_bytes_with_nul(b"hello"); 1097 | /// assert!(cstr.is_err()); 1098 | /// ``` 1099 | /// 1100 | /// Creating a `CStr` with an interior nul byte is an error: 1101 | /// 1102 | /// ``` 1103 | /// use cstr_core::CStr; 1104 | /// 1105 | /// let cstr = CStr::from_bytes_with_nul(b"he\0llo\0"); 1106 | /// assert!(cstr.is_err()); 1107 | /// ``` 1108 | #[cfg(not(feature = "nightly"))] 1109 | pub fn from_bytes_with_nul(bytes: &[u8]) -> Result<&CStr, FromBytesWithNulError> { 1110 | let nul_pos = memchr(0, bytes); 1111 | if let Some(nul_pos) = nul_pos { 1112 | if nul_pos + 1 != bytes.len() { 1113 | return Err(FromBytesWithNulError::interior_nul(nul_pos)); 1114 | } 1115 | Ok(unsafe { CStr::from_bytes_with_nul_unchecked(bytes) }) 1116 | } else { 1117 | Err(FromBytesWithNulError::not_nul_terminated()) 1118 | } 1119 | } 1120 | 1121 | /// Unsafely creates a C string wrapper from a byte slice. 1122 | /// 1123 | /// This function will cast the provided `bytes` to a `CStr` wrapper without 1124 | /// performing any sanity checks. The provided slice **must** be nul-terminated 1125 | /// and not contain any interior nul bytes. 1126 | /// 1127 | /// # Examples 1128 | /// 1129 | /// ``` 1130 | /// use cstr_core::{CStr, CString}; 1131 | /// 1132 | /// unsafe { 1133 | /// let cstring = CString::new("hello").expect("CString::new failed"); 1134 | /// let cstr = CStr::from_bytes_with_nul_unchecked(cstring.to_bytes_with_nul()); 1135 | /// assert_eq!(cstr, &*cstring); 1136 | /// } 1137 | /// ``` 1138 | #[cfg(feature = "nightly")] 1139 | #[inline] 1140 | pub const unsafe fn from_bytes_with_nul_unchecked(bytes: &[u8]) -> &CStr { 1141 | &*(bytes as *const [u8] as *const CStr) 1142 | } 1143 | 1144 | /// Unsafely creates a C string wrapper from a byte slice. 1145 | /// 1146 | /// This function will cast the provided `bytes` to a `CStr` wrapper without 1147 | /// performing any sanity checks. The provided slice **must** be nul-terminated 1148 | /// and not contain any interior nul bytes. 1149 | /// 1150 | /// # Examples 1151 | /// 1152 | /// ``` 1153 | /// use cstr_core::{CStr, CString}; 1154 | /// 1155 | /// unsafe { 1156 | /// let cstring = CString::new("hello").expect("CString::new failed"); 1157 | /// let cstr = CStr::from_bytes_with_nul_unchecked(cstring.to_bytes_with_nul()); 1158 | /// assert_eq!(cstr, &*cstring); 1159 | /// } 1160 | /// ``` 1161 | #[cfg(not(feature = "nightly"))] 1162 | #[inline] 1163 | pub unsafe fn from_bytes_with_nul_unchecked(bytes: &[u8]) -> &CStr { 1164 | &*(bytes as *const [u8] as *const CStr) 1165 | } 1166 | 1167 | /// Returns the inner pointer to this C string. 1168 | /// 1169 | /// The returned pointer will be valid for as long as `self` is, and points 1170 | /// to a contiguous region of memory terminated with a 0 byte to represent 1171 | /// the end of the string. 1172 | /// 1173 | /// **WARNING** 1174 | /// 1175 | /// The returned pointer is read-only; writing to it (including passing it 1176 | /// to C code that writes to it) causes undefined behavior. 1177 | /// 1178 | /// It is your responsibility to make sure that the underlying memory is not 1179 | /// freed too early. For example, the following code will cause undefined 1180 | /// behavior when `ptr` is used inside the `unsafe` block: 1181 | /// 1182 | /// ```no_run 1183 | /// # #![allow(unused_must_use)] 1184 | /// use cstr_core::CString; 1185 | /// 1186 | /// let ptr = CString::new("Hello").expect("CString::new failed").as_ptr(); 1187 | /// unsafe { 1188 | /// // `ptr` is dangling 1189 | /// *ptr; 1190 | /// } 1191 | /// ``` 1192 | /// 1193 | /// This happens because the pointer returned by `as_ptr` does not carry any 1194 | /// lifetime information and the [`CString`] is deallocated immediately after 1195 | /// the `CString::new("Hello").expect("CString::new failed").as_ptr()` expression is evaluated. 1196 | /// To fix the problem, bind the `CString` to a local variable: 1197 | /// 1198 | /// ```no_run 1199 | /// # #![allow(unused_must_use)] 1200 | /// use cstr_core::CString; 1201 | /// 1202 | /// let hello = CString::new("Hello").expect("CString::new failed"); 1203 | /// let ptr = hello.as_ptr(); 1204 | /// unsafe { 1205 | /// // `ptr` is valid because `hello` is in scope 1206 | /// *ptr; 1207 | /// } 1208 | /// ``` 1209 | /// 1210 | /// This way, the lifetime of the `CString` in `hello` encompasses 1211 | /// the lifetime of `ptr` and the `unsafe` block. 1212 | /// 1213 | /// [`CString`]: struct.CString.html 1214 | #[inline] 1215 | pub const fn as_ptr(&self) -> *const c_char { 1216 | self.inner.as_ptr() 1217 | } 1218 | 1219 | /// Converts this C string to a byte slice. 1220 | /// 1221 | /// The returned slice will **not** contain the trailing nul terminator that this C 1222 | /// string has. 1223 | /// 1224 | /// > **Note**: This method is currently implemented as a constant-time 1225 | /// > cast, but it is planned to alter its definition in the future to 1226 | /// > perform the length calculation whenever this method is called. 1227 | /// 1228 | /// # Examples 1229 | /// 1230 | /// ``` 1231 | /// use cstr_core::CStr; 1232 | /// 1233 | /// let cstr = CStr::from_bytes_with_nul(b"foo\0").expect("CStr::from_bytes_with_nul failed"); 1234 | /// assert_eq!(cstr.to_bytes(), b"foo"); 1235 | /// ``` 1236 | #[inline] 1237 | #[cfg(not(feature = "nightly"))] 1238 | pub fn to_bytes(&self) -> &[u8] { 1239 | let bytes = self.to_bytes_with_nul(); 1240 | &bytes[..bytes.len() - 1] 1241 | } 1242 | 1243 | /// Converts this C string to a byte slice. 1244 | /// 1245 | /// The returned slice will **not** contain the trailing nul terminator that this C 1246 | /// string has. 1247 | /// 1248 | /// > **Note**: This method is currently implemented as a constant-time 1249 | /// > cast, but it is planned to alter its definition in the future to 1250 | /// > perform the length calculation whenever this method is called. 1251 | /// 1252 | /// # Examples 1253 | /// 1254 | /// ``` 1255 | /// use cstr_core::CStr; 1256 | /// 1257 | /// let cstr = CStr::from_bytes_with_nul(b"foo\0").expect("CStr::from_bytes_with_nul failed"); 1258 | /// assert_eq!(cstr.to_bytes(), b"foo"); 1259 | /// ``` 1260 | #[inline] 1261 | #[cfg(feature = "nightly")] 1262 | pub const fn to_bytes(&self) -> &[u8] { 1263 | let bytes = self.to_bytes_with_nul(); 1264 | // unsafe: This is just like [:len - 1] (but const usable), and any underflow of the `- 1` 1265 | // is avoided by the type's guarantee that there is a trailing nul byte. 1266 | unsafe { 1267 | slice::from_raw_parts(bytes.as_ptr(), bytes.len() - 1) 1268 | } 1269 | } 1270 | 1271 | /// Converts this C string to a byte slice containing the trailing 0 byte. 1272 | /// 1273 | /// This function is the equivalent of [`to_bytes`] except that it will retain 1274 | /// the trailing nul terminator instead of chopping it off. 1275 | /// 1276 | /// > **Note**: This method is currently implemented as a 0-cost cast, but 1277 | /// > it is planned to alter its definition in the future to perform the 1278 | /// > length calculation whenever this method is called. 1279 | /// 1280 | /// [`to_bytes`]: #method.to_bytes 1281 | /// 1282 | /// # Examples 1283 | /// 1284 | /// ``` 1285 | /// use cstr_core::CStr; 1286 | /// 1287 | /// let cstr = CStr::from_bytes_with_nul(b"foo\0").expect("CStr::from_bytes_with_nul failed"); 1288 | /// assert_eq!(cstr.to_bytes_with_nul(), b"foo\0"); 1289 | /// ``` 1290 | #[inline] 1291 | #[cfg(feature = "nightly")] 1292 | pub const fn to_bytes_with_nul(&self) -> &[u8] { 1293 | unsafe { &*(&self.inner as *const [c_char] as *const [u8]) } 1294 | } 1295 | 1296 | /// Converts this C string to a byte slice containing the trailing 0 byte. 1297 | /// 1298 | /// This function is the equivalent of [`to_bytes`] except that it will retain 1299 | /// the trailing nul terminator instead of chopping it off. 1300 | /// 1301 | /// > **Note**: This method is currently implemented as a 0-cost cast, but 1302 | /// > it is planned to alter its definition in the future to perform the 1303 | /// > length calculation whenever this method is called. 1304 | /// 1305 | /// [`to_bytes`]: #method.to_bytes 1306 | /// 1307 | /// # Examples 1308 | /// 1309 | /// ``` 1310 | /// use cstr_core::CStr; 1311 | /// 1312 | /// let cstr = CStr::from_bytes_with_nul(b"foo\0").expect("CStr::from_bytes_with_nul failed"); 1313 | /// assert_eq!(cstr.to_bytes_with_nul(), b"foo\0"); 1314 | /// ``` 1315 | #[inline] 1316 | #[cfg(not(feature = "nightly"))] 1317 | pub fn to_bytes_with_nul(&self) -> &[u8] { 1318 | unsafe { &*(&self.inner as *const [c_char] as *const [u8]) } 1319 | } 1320 | 1321 | /// Yields a [`&str`] slice if the `CStr` contains valid UTF-8. 1322 | /// 1323 | /// If the contents of the `CStr` are valid UTF-8 data, this 1324 | /// function will return the corresponding [`&str`] slice. Otherwise, 1325 | /// it will return an error with details of where UTF-8 validation failed. 1326 | /// 1327 | /// # Examples 1328 | /// 1329 | /// ``` 1330 | /// use cstr_core::CStr; 1331 | /// 1332 | /// let cstr = CStr::from_bytes_with_nul(b"foo\0").expect("CStr::from_bytes_with_nul failed"); 1333 | /// assert_eq!(cstr.to_str(), Ok("foo")); 1334 | /// ``` 1335 | #[cfg(not(feature = "nightly"))] 1336 | pub fn to_str(&self) -> Result<&str, Utf8Error> { 1337 | // N.B., when `CStr` is changed to perform the length check in `.to_bytes()` 1338 | // instead of in `from_ptr()`, it may be worth considering if this should 1339 | // be rewritten to do the UTF-8 check inline with the length calculation 1340 | // instead of doing it afterwards. 1341 | str::from_utf8(self.to_bytes()) 1342 | } 1343 | 1344 | /// Yields a [`&str`] slice if the `CStr` contains valid UTF-8. 1345 | /// 1346 | /// If the contents of the `CStr` are valid UTF-8 data, this 1347 | /// function will return the corresponding [`&str`] slice. Otherwise, 1348 | /// it will return an error with details of where UTF-8 validation failed. 1349 | /// 1350 | /// # Examples 1351 | /// 1352 | /// ``` 1353 | /// use cstr_core::CStr; 1354 | /// 1355 | /// let cstr = CStr::from_bytes_with_nul(b"foo\0").expect("CStr::from_bytes_with_nul failed"); 1356 | /// assert_eq!(cstr.to_str(), Ok("foo")); 1357 | /// ``` 1358 | #[cfg(feature = "nightly")] 1359 | pub const fn to_str(&self) -> Result<&str, Utf8Error> { 1360 | // N.B., when `CStr` is changed to perform the length check in `.to_bytes()` 1361 | // instead of in `from_ptr()`, it may be worth considering if this should 1362 | // be rewritten to do the UTF-8 check inline with the length calculation 1363 | // instead of doing it afterwards. 1364 | str::from_utf8(self.to_bytes()) 1365 | } 1366 | 1367 | /// Converts a `CStr` into a [`Cow`]`<`[`str`]`>`. 1368 | /// 1369 | /// If the contents of the `CStr` are valid UTF-8 data, this 1370 | /// function will return a [`Cow`]`::`[`Borrowed`]`(`[`&str`]`)` 1371 | /// with the corresponding [`&str`] slice. Otherwise, it will 1372 | /// replace any invalid UTF-8 sequences with 1373 | /// [`U+FFFD REPLACEMENT CHARACTER`][U+FFFD] and return a 1374 | /// [`Cow`]`::`[`Owned`]`(`[`String`]`)` with the result. 1375 | /// 1376 | /// [`Borrowed`]: Cow::Borrowed 1377 | /// [`Owned`]: Cow::Owned 1378 | /// [U+FFFD]: core::char::REPLACEMENT_CHARACTER 1379 | /// 1380 | /// # Examples 1381 | /// 1382 | /// Calling `to_string_lossy` on a `CStr` containing valid UTF-8: 1383 | /// 1384 | /// ``` 1385 | /// use std::borrow::Cow; 1386 | /// use cstr_core::CStr; 1387 | /// 1388 | /// let cstr = CStr::from_bytes_with_nul(b"Hello World\0") 1389 | /// .expect("CStr::from_bytes_with_nul failed"); 1390 | /// assert_eq!(cstr.to_string_lossy(), Cow::Borrowed("Hello World")); 1391 | /// ``` 1392 | /// 1393 | /// Calling `to_string_lossy` on a `CStr` containing invalid UTF-8: 1394 | /// 1395 | /// ``` 1396 | /// use std::borrow::Cow; 1397 | /// use cstr_core::CStr; 1398 | /// 1399 | /// let cstr = CStr::from_bytes_with_nul(b"Hello \xF0\x90\x80World\0") 1400 | /// .expect("CStr::from_bytes_with_nul failed"); 1401 | /// assert_eq!( 1402 | /// cstr.to_string_lossy(), 1403 | /// Cow::Owned(String::from("Hello �World")) as Cow<'_, str> 1404 | /// ); 1405 | /// ``` 1406 | #[cfg(feature = "alloc")] 1407 | pub fn to_string_lossy(&self) -> Cow<'_, str> { 1408 | String::from_utf8_lossy(self.to_bytes()) 1409 | } 1410 | 1411 | /// Converts a [`Box`]`` into a [`CString`] without copying or allocating. 1412 | /// 1413 | /// [`CString`]: struct.CString.html 1414 | /// 1415 | /// # Examples 1416 | /// 1417 | /// ``` 1418 | /// use cstr_core::CString; 1419 | /// 1420 | /// let c_string = CString::new(b"foo".to_vec()).expect("CString::new failed"); 1421 | /// let boxed = c_string.into_boxed_c_str(); 1422 | /// assert_eq!(boxed.into_c_string(), CString::new("foo").expect("CString::new failed")); 1423 | /// ``` 1424 | #[cfg(feature = "alloc")] 1425 | pub fn into_c_string(self: Box) -> CString { 1426 | let raw = Box::into_raw(self) as *mut [u8]; 1427 | CString { 1428 | inner: unsafe { Box::from_raw(raw) }, 1429 | } 1430 | } 1431 | } 1432 | 1433 | impl PartialEq for CStr { 1434 | fn eq(&self, other: &CStr) -> bool { 1435 | self.to_bytes().eq(other.to_bytes()) 1436 | } 1437 | } 1438 | impl Eq for CStr {} 1439 | impl PartialOrd for CStr { 1440 | fn partial_cmp(&self, other: &CStr) -> Option { 1441 | self.to_bytes().partial_cmp(&other.to_bytes()) 1442 | } 1443 | } 1444 | impl Ord for CStr { 1445 | fn cmp(&self, other: &CStr) -> Ordering { 1446 | self.to_bytes().cmp(&other.to_bytes()) 1447 | } 1448 | } 1449 | 1450 | #[cfg(feature = "alloc")] 1451 | impl ToOwned for CStr { 1452 | type Owned = CString; 1453 | 1454 | fn to_owned(&self) -> CString { 1455 | CString { 1456 | inner: self.to_bytes_with_nul().into(), 1457 | } 1458 | } 1459 | } 1460 | 1461 | #[cfg(feature = "alloc")] 1462 | impl From<&CStr> for CString { 1463 | fn from(s: &CStr) -> CString { 1464 | s.to_owned() 1465 | } 1466 | } 1467 | 1468 | #[cfg(feature = "alloc")] 1469 | impl ops::Index for CString { 1470 | type Output = CStr; 1471 | 1472 | #[inline] 1473 | fn index(&self, _index: ops::RangeFull) -> &CStr { 1474 | self 1475 | } 1476 | } 1477 | 1478 | impl AsRef for CStr { 1479 | #[inline] 1480 | fn as_ref(&self) -> &CStr { 1481 | self 1482 | } 1483 | } 1484 | 1485 | #[cfg(feature = "alloc")] 1486 | impl AsRef for CString { 1487 | #[inline] 1488 | fn as_ref(&self) -> &CStr { 1489 | self 1490 | } 1491 | } 1492 | 1493 | #[inline] 1494 | #[doc(hidden)] 1495 | pub const fn bytes_are_valid(bytes: &[u8]) -> bool { 1496 | if bytes.len() == 0 || bytes[bytes.len() - 1] != 0 { 1497 | return false; 1498 | } 1499 | let mut index = 0; 1500 | // No for loops yet in const functions 1501 | while index < bytes.len() - 1 { 1502 | if bytes[index] == 0 { 1503 | return false; 1504 | } 1505 | index += 1; 1506 | } 1507 | true 1508 | } 1509 | 1510 | /// Generate a [CStr] at compile time that is guaranteed to be correct. The given argument should be a string literal with no `\0` bytes. 1511 | /// 1512 | /// This macro validates at compile time that the given string does not contain `\0` and automatically appends `\0`. 1513 | /// 1514 | /// ```rust 1515 | /// let str: &cstr_core::CStr = cstr_core::cstr!("Hello world!"); 1516 | /// assert_eq!("Hello world!", str.to_str().unwrap()); 1517 | /// ``` 1518 | /// 1519 | /// **note**: if the string contains `\0` bytes, the error looks like: 1520 | /// ```bash 1521 | /// error[E0080]: evaluation of constant value failed 1522 | /// --> src/lib.rs:1358:29 1523 | /// | 1524 | /// 4 | let str: &cstr_core::CStr = cstr_core::cstr!("Hello \0world!"); 1525 | /// | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ attempt to compute `0_usize - 1_usize`, which would overflow 1526 | /// | 1527 | /// = note: this error originates in the macro `cstr_core::cstr` (in Nightly builds, run with -Z macro-backtrace for more info) 1528 | /// ``` 1529 | #[macro_export] 1530 | macro_rules! cstr { 1531 | ($e:expr) => {{ 1532 | const STR: &[u8] = concat!($e, "\0").as_bytes(); 1533 | const STR_VALID: bool = $crate::bytes_are_valid(STR); 1534 | let _ = [(); 0 - (!(STR_VALID) as usize)]; 1535 | unsafe { 1536 | $crate::CStr::from_bytes_with_nul_unchecked(STR) 1537 | } 1538 | }} 1539 | } 1540 | 1541 | #[cfg(test)] 1542 | mod tests { 1543 | use super::*; 1544 | use std::borrow::Cow::{Borrowed, Owned}; 1545 | use std::collections::hash_map::DefaultHasher; 1546 | use std::hash::{Hash, Hasher}; 1547 | use std::{format, vec}; 1548 | 1549 | #[test] 1550 | fn c_to_rust() { 1551 | let data = b"123\0"; 1552 | let ptr = data.as_ptr() as *const c_char; 1553 | unsafe { 1554 | assert_eq!(CStr::from_ptr(ptr).to_bytes(), b"123"); 1555 | assert_eq!(CStr::from_ptr(ptr).to_bytes_with_nul(), b"123\0"); 1556 | } 1557 | } 1558 | 1559 | #[test] 1560 | fn simple() { 1561 | let s = CString::new("1234").unwrap(); 1562 | assert_eq!(s.as_bytes(), b"1234"); 1563 | assert_eq!(s.as_bytes_with_nul(), b"1234\0"); 1564 | } 1565 | 1566 | #[test] 1567 | fn build_with_zero1() { 1568 | assert!(CString::new(&b"\0"[..]).is_err()); 1569 | } 1570 | #[test] 1571 | fn build_with_zero2() { 1572 | assert!(CString::new(vec![0]).is_err()); 1573 | } 1574 | 1575 | #[test] 1576 | fn build_with_zero3() { 1577 | unsafe { 1578 | let s = CString::from_vec_unchecked(vec![0]); 1579 | assert_eq!(s.as_bytes(), b"\0"); 1580 | } 1581 | } 1582 | 1583 | #[test] 1584 | fn formatted() { 1585 | let s = CString::new(&b"abc\x01\x02\n\xE2\x80\xA6\xFF"[..]).unwrap(); 1586 | assert_eq!(format!("{:?}", s), r#""abc\x01\x02\n\xe2\x80\xa6\xff""#); 1587 | } 1588 | 1589 | #[test] 1590 | fn borrowed() { 1591 | unsafe { 1592 | let s = CStr::from_ptr(b"12\0".as_ptr() as *const _); 1593 | assert_eq!(s.to_bytes(), b"12"); 1594 | assert_eq!(s.to_bytes_with_nul(), b"12\0"); 1595 | } 1596 | } 1597 | 1598 | #[test] 1599 | fn to_str() { 1600 | let data = b"123\xE2\x80\xA6\0"; 1601 | let ptr = data.as_ptr() as *const c_char; 1602 | unsafe { 1603 | assert_eq!(CStr::from_ptr(ptr).to_str(), Ok("123…")); 1604 | assert_eq!(CStr::from_ptr(ptr).to_string_lossy(), Borrowed("123…")); 1605 | } 1606 | let data = b"123\xE2\0"; 1607 | let ptr = data.as_ptr() as *const c_char; 1608 | unsafe { 1609 | assert!(CStr::from_ptr(ptr).to_str().is_err()); 1610 | assert_eq!( 1611 | CStr::from_ptr(ptr).to_string_lossy(), 1612 | Owned::(format!("123\u{FFFD}")) 1613 | ); 1614 | } 1615 | } 1616 | 1617 | #[test] 1618 | fn to_owned() { 1619 | let data = b"123\0"; 1620 | let ptr = data.as_ptr() as *const c_char; 1621 | 1622 | let owned = unsafe { CStr::from_ptr(ptr).to_owned() }; 1623 | assert_eq!(owned.as_bytes_with_nul(), data); 1624 | } 1625 | 1626 | #[test] 1627 | fn equal_hash() { 1628 | let data = b"123\xE2\xFA\xA6\0"; 1629 | let ptr = data.as_ptr() as *const c_char; 1630 | let cstr: &'static CStr = unsafe { CStr::from_ptr(ptr) }; 1631 | 1632 | let mut s = DefaultHasher::new(); 1633 | cstr.hash(&mut s); 1634 | let cstr_hash = s.finish(); 1635 | let mut s = DefaultHasher::new(); 1636 | CString::new(&data[..data.len() - 1]).unwrap().hash(&mut s); 1637 | let cstring_hash = s.finish(); 1638 | 1639 | assert_eq!(cstr_hash, cstring_hash); 1640 | } 1641 | 1642 | #[test] 1643 | fn from_bytes_with_nul() { 1644 | let data = b"123\0"; 1645 | let cstr = CStr::from_bytes_with_nul(data); 1646 | assert_eq!(cstr.map(CStr::to_bytes), Ok(&b"123"[..])); 1647 | let cstr = CStr::from_bytes_with_nul(data); 1648 | assert_eq!(cstr.map(CStr::to_bytes_with_nul), Ok(&b"123\0"[..])); 1649 | 1650 | unsafe { 1651 | let cstr = CStr::from_bytes_with_nul(data); 1652 | let cstr_unchecked = CStr::from_bytes_with_nul_unchecked(data); 1653 | assert_eq!(cstr, Ok(cstr_unchecked)); 1654 | } 1655 | } 1656 | 1657 | #[test] 1658 | fn from_bytes_with_nul_unterminated() { 1659 | let data = b"123"; 1660 | let cstr = CStr::from_bytes_with_nul(data); 1661 | assert!(cstr.is_err()); 1662 | } 1663 | 1664 | #[test] 1665 | fn from_bytes_with_nul_interior() { 1666 | let data = b"1\023\0"; 1667 | let cstr = CStr::from_bytes_with_nul(data); 1668 | assert!(cstr.is_err()); 1669 | } 1670 | 1671 | #[test] 1672 | fn into_boxed() { 1673 | let orig: &[u8] = b"Hello, world!\0"; 1674 | let cstr = CStr::from_bytes_with_nul(orig).unwrap(); 1675 | let boxed: Box = Box::from(cstr); 1676 | let cstring = cstr.to_owned().into_boxed_c_str().into_c_string(); 1677 | assert_eq!(cstr, &*boxed); 1678 | assert_eq!(&*boxed, &*cstring); 1679 | assert_eq!(&*cstring, cstr); 1680 | } 1681 | 1682 | #[test] 1683 | fn boxed_default() { 1684 | let boxed = >::default(); 1685 | assert_eq!(boxed.to_bytes_with_nul(), &[0]); 1686 | } 1687 | 1688 | #[test] 1689 | #[cfg(feature = "alloc")] 1690 | #[cfg(feature = "arc")] 1691 | fn into_rc() { 1692 | let orig: &[u8] = b"Hello, world!\0"; 1693 | let cstr = CStr::from_bytes_with_nul(orig).unwrap(); 1694 | let rc: Rc = Rc::from(cstr); 1695 | let arc: Arc = Arc::from(cstr); 1696 | 1697 | assert_eq!(&*rc, cstr); 1698 | assert_eq!(&*arc, cstr); 1699 | 1700 | let rc2: Rc = Rc::from(cstr.to_owned()); 1701 | let arc2: Arc = Arc::from(cstr.to_owned()); 1702 | 1703 | assert_eq!(&*rc2, cstr); 1704 | assert_eq!(&*arc2, cstr); 1705 | } 1706 | 1707 | #[test] 1708 | #[cfg(feature = "nightly")] 1709 | fn const_cstr() { 1710 | const TESTING_CSTR: &CStr = 1711 | unsafe { CStr::from_bytes_with_nul_unchecked(b"Hello world!\0") }; 1712 | let _ = TESTING_CSTR.as_ptr(); 1713 | } 1714 | } 1715 | --------------------------------------------------------------------------------