diff --git a/.travis.yml b/.travis.yml index b6989f6..3a6eab5 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,7 +4,7 @@ rust: - nightly matrix: allow_failures: - - rust: nightly + - rust: nightly script: - cargo build --verbose - - cargo test --lib --verbose + - cargo test --verbose diff --git a/Cargo.toml b/Cargo.toml index 5263947..8d03bd4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,13 +1,14 @@ [package] name = "clucstr" -version = "0.1.6" +version = "0.1.7" authors = ["Денис Котляров <#Ulin Project 18, denis2005991@gmail.com>"] repository = "https://github.com/clucompany/cluCStr.git" +edition = "2018" license = "Apache-2.0" readme = "README.md" -description = "Creation of strings C with zero cost. A plug-in for the rust compiler." +description = "Safe creation of 'CStr' with zero cost at a compilation stage with check of zero bytes and a possibility of communication of several values." keywords = ["cstr", "clucstr", "create_cstr", "clucompany"] categories = ["development-tools::ffi"] diff --git a/LICENSE b/LICENSE index 261eeb9..20f7785 100644 --- a/LICENSE +++ b/LICENSE @@ -1,190 +1,190 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. Copyright [yyyy] [name of copyright owner] @@ -192,7 +192,7 @@ you may not use this file except in compliance with the License. You may obtain a copy of the License at - http://www.apache.org/licenses/LICENSE-2.0 + http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, diff --git a/README.md b/README.md index d2a5d9c..b84eae3 100644 --- a/README.md +++ b/README.md @@ -4,14 +4,13 @@ [![crates.io](http://meritbadge.herokuapp.com/clucstr)](https://crates.io/crates/clucstr) [![Documentation](https://docs.rs/clucstr/badge.svg)](https://docs.rs/clucstr) -Creation of strings C with zero cost. A plug-in for the rust compiler. +Safe creation of 'CStr' with zero cost at a compilation stage with check of zero bytes and a possibility of communication of several values. # Features -1. The transparent creation of the C strings with zero cost. -2. Check of the C lines at the level of the compiler. -3. Convenient macro for creation of lines. -4. Plug-in for the compiler. - +1. Creation of safe CStr at a compilation stage. +2. Check of zero bytes at a stage of compilation or checks of "Rls or Rust check". +3. Concatenation of several values, different types: [u8], & 'static str, u8, i8, (0 without specifying the type). +4. All actions happen at a compilation stage, processor time is not required. # Use ``` @@ -21,124 +20,137 @@ Creation of strings C with zero cost. A plug-in for the rust compiler. use std::ffi::CStr; fn main() { - let c_str = cstr!("cluWorld!!!"); - let c_str_barr = cstr!(b"cluWorld!!!"); - let c_str_b = cstr!(b'A'); -} -``` - -``` -#![feature(plugin)] -#![plugin(clucstr)] - -use std::ffi::CStr; - -fn main() { - println_str(cstr!("cluWorld!!!")); - //CSTR "cluWorld!!!" - //CArray [99, 108, 117, 87, 111, 114, 108, 100, 33, 33, 33, 0] 12 - - println_str(cstr!(b"cluWorld!!!")); - //CSTR "cluWorld!!!" - //CArray [99, 108, 117, 87, 111, 114, 108, 100, 33, 33, 33, 0] 12 - - println_str(cstr!(b'A')); - //CSTR "A" - //CArray [65, 0] 2 + let c_str = cstr!("cluWorld"); + //"cluWorld" <-- [99, 108, 117, 87, 111, 114, 108, 100, 0], len:9 + + let c_str2 = cstr!("cluWorld\0"); + //"cluWorld" <-- [99, 108, 117, 87, 111, 114, 108, 100, 0], len:9 + + let c_str3 = cstr!("clu", b"World"); + //"cluWorld" <-- [99, 108, 117, 87, 111, 114, 108, 100, 0], len:9 + + let c_str4 = cstr!( + b'c', b'l', b'u', + b'W', b'o', b'r', b'l', b'd', + 0 + ); + //"cluWorld" <-- [99, 108, 117, 87, 111, 114, 108, 100, 0], len:9 + + let c_str5 = cstr!( + "clu", + //It is possible to insert such values as: [u8], & 'static str, u8, i8, (0 without specifying the type). + + b'W', b'o', b'r', b'l', b"d\0" + //The zero byte is automatically added, it is possible to write it, and it is possible not to write. + //It is forbidden to insert zero byte in the middle or at the beginning of a line. + ); + //"cluWorld" <-- [99, 108, 117, 87, 111, 114, 108, 100, 0], len:9 + + my_function(c_str); + my_function(c_str2); + my_function(c_str3); + my_function(c_str4); + my_function(c_str5); } - -fn println_str(cstr: &CStr) { - println!("CSTR {:?}", cstr); - - let cstr_array = cstr.to_bytes_with_nul(); - println!("CArray {:?} {}", cstr_array, cstr_array.len()); - println!(); +fn my_function(a: &'static CStr) { + //'static --> it is possible not to write. + + let c_arr = a.to_bytes_with_nul(); + println!("{:?} <-- array: {:?}, len: {}", a, c_arr, c_arr.len()); } ``` # Panic ``` + #![feature(plugin)] #![plugin(clucstr)] +#[allow(unused_imports)] use std::ffi::CStr; fn main() { - let c_str = cstr!("\0Test_str"); - // PANIC! A null byte was found. + //let c_str = cstr!("cluW\0orld"); + //PANIC! trailing byte detected - let c_str = cstr!(b"\0Test_array"); - // PANIC! A null byte was found. + //let c_str2 = cstr!("cluWorld\0\0"); + //PANIC! trailing byte detected - let c_str = cstr!("Test_str\0"); - //It is allowed to write since the null byte is at the end. + //let c_str3 = cstr!("\0clu", b"W\0orld"); + //PANIC! trailing byte detected - let c_str = cstr!(b"Test_str\0"); - //It is allowed to write since the null byte is at the end. + /*let c_str4 = cstr!( + b'c', b'l', b'u', 0u8, + b'W', b'o', b'r', b'l', b'd', + 0 + );*/ + //PANIC! trailing byte detected } ``` # Benchmarking -cstr_macros - old method of converting strings to cstr. Note that in CStr, there is no protection from null bytes. -cstr_plugin - new method for converting strings to cstr. ``` -#![feature(plugin)] -#![plugin(clucstr)] #![feature(test)] -extern crate test; -use std::ffi::CStr; - - -#[macro_export] -macro_rules! cstr_macro { - ($s:expr) => { - unsafe { - ::std::ffi::CStr::from_ptr( - concat!($s, "\0") - as *const str - as *const [::std::os::raw::c_char] - as *const ::std::os::raw::c_char - ) - } - }; -} +#![feature(plugin)] +#![plugin(clucstr)] #[cfg(test)] mod tests { - use super::*; - use test::Bencher; - - #[bench] - fn cstr_plugin(b: &mut Bencher) { - b.iter(|| { - for _a in 0..10 { - let _cstr0 = cstr!(b"test"); - } - }); - } - #[bench] - fn cstr_macros(b: &mut Bencher) { - b.iter(|| { - for _a in 0..10 { - let _cstr0 = cstr_macro!("test"); - } - }); - } + use super::*; + use tests::test::Bencher; + use std::ffi::CStr; + + extern crate test; + + + + macro_rules! unsafe_cstr { + ($s:expr) => { + unsafe { + ::std::ffi::CStr::from_ptr( + concat!($s, "\0") + as *const str + as *const [::std::os::raw::c_char] + as *const ::std::os::raw::c_char + ) + } + }; + } + + #[bench] + fn cstr_plugin(b: &mut Bencher) { + b.iter(|| { + for _a in 0..10 { + let _cstr0 = cstr!(b"test"); + } + }); + } + #[bench] + fn cstr_macros(b: &mut Bencher) { + b.iter(|| { + for _a in 0..10 { + let _cstr0 = unsafe_cstr!("test"); + } + }); + } } ``` running 2 tests -test tests::cstr_macros ... bench: 90 ns/iter (+/- 14) +test tests::cstr_macros ... bench: 67 ns/iter (+/- 1) !Attention ns > 0, full unsafe, no guarantees + +test tests::cstr_plugin ... bench: 0 ns/iter (+/- 0) !Attention ns == 0, plus zero byte checking and plus concatenation -test tests::cstr_plugin ... bench: 0 ns/iter (+/- 0) +# Launch benchmark: +cargo bench --example bench # License -Copyright 2018 #UlinProject Денис Котляров +Copyright 2019 #UlinProject Denis Kotlyarov (Денис Котляров) -Licensed under the Apache License, Version 2.0 +Licensed under the Apache License, Version 2.0 \ No newline at end of file diff --git a/examples/bench.rs b/examples/bench.rs new file mode 100644 index 0000000..e6b4b0f --- /dev/null +++ b/examples/bench.rs @@ -0,0 +1,49 @@ + + +//RUN cargo bench --example bench +#![feature(test)] + +#![feature(plugin)] +#![plugin(clucstr)] + + +#[cfg(test)] +mod tests { + use super::*; + use tests::test::Bencher; + use std::ffi::CStr; + + extern crate test; + + + + macro_rules! unsafe_cstr { + ($s:expr) => { + unsafe { + ::std::ffi::CStr::from_ptr( + concat!($s, "\0") + as *const str + as *const [::std::os::raw::c_char] + as *const ::std::os::raw::c_char + ) + } + }; + } + + #[bench] + fn cstr_plugin(b: &mut Bencher) { + b.iter(|| { + for _a in 0..10 { + let _cstr0 = cstr!(b"test"); + } + }); + } + #[bench] + fn cstr_macros(b: &mut Bencher) { + b.iter(|| { + for _a in 0..10 { + let _cstr0 = unsafe_cstr!("test"); + } + }); + } +} \ No newline at end of file diff --git a/examples/panic.rs b/examples/panic.rs new file mode 100644 index 0000000..3c9834d --- /dev/null +++ b/examples/panic.rs @@ -0,0 +1,28 @@ + +#![feature(plugin)] +#![plugin(clucstr)] + +#[allow(unused_imports)] +use std::ffi::CStr; + +//ATTENTION!!! +// +//For display of panic 'RLS or Rust Check' it is required to uncomment functions. + +fn main() { + //let c_str = cstr!("cluW\0orld"); + //PANIC! trailing byte detected + + //let c_str2 = cstr!("cluWorld\0\0"); + //PANIC! trailing byte detected + + //let c_str3 = cstr!("\0clu", b"W\0orld"); + //PANIC! trailing byte detected + + /*let c_str4 = cstr!( + b'c', b'l', b'u', 0u8, + b'W', b'o', b'r', b'l', b'd', + 0 + );*/ + //PANIC! trailing byte detected +} \ No newline at end of file diff --git a/examples/use.rs b/examples/use.rs index f3a5b3f..8080c7b 100644 --- a/examples/use.rs +++ b/examples/use.rs @@ -5,11 +5,42 @@ use std::ffi::CStr; fn main() { - let c_str = cstr!(12u8); + let c_str = cstr!("cluWorld"); + //"cluWorld" <-- [99, 108, 117, 87, 111, 114, 108, 100, 0], len:9 - my_function(c_str); + let c_str2 = cstr!("cluWorld\0"); + //"cluWorld" <-- [99, 108, 117, 87, 111, 114, 108, 100, 0], len:9 + + let c_str3 = cstr!("clu", b"World"); + //"cluWorld" <-- [99, 108, 117, 87, 111, 114, 108, 100, 0], len:9 + + let c_str4 = cstr!( + b'c', b'l', b'u', + b'W', b'o', b'r', b'l', b'd', + 0 + ); + //"cluWorld" <-- [99, 108, 117, 87, 111, 114, 108, 100, 0], len:9 + + let c_str5 = cstr!( + "clu", + //It is possible to insert such values as: [u8], & 'static str, u8, i8, (0 without specifying the type). + + b'W', b'o', b'r', b'l', b"d\0" + //The zero byte is automatically added, it is possible to write it, and it is possible not to write. + //It is forbidden to insert zero byte in the middle or at the beginning of a line. + ); + //"cluWorld" <-- [99, 108, 117, 87, 111, 114, 108, 100, 0], len:9 + + my_function(c_str); + my_function(c_str2); + my_function(c_str3); + my_function(c_str4); + my_function(c_str5); } -fn my_function>(a: A) { - println!("{:?}", a.as_ref()); +fn my_function(a: &'static CStr) { + //'static --> it is possible not to write. + + let c_arr = a.to_bytes_with_nul(); + println!("{:?} <-- array: {:?}, len: {}", a, c_arr, c_arr.len()); } \ No newline at end of file diff --git a/src/lib.rs b/src/lib.rs index e9ef798..8676e1f 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -4,7 +4,7 @@ //you may not use this file except in compliance with the License. //You may obtain a copy of the License at -// http://www.apache.org/licenses/LICENSE-2.0 +// http://www.apache.org/licenses/LICENSE-2.0 //Unless required by applicable law or agreed to in writing, software //distributed under the License is distributed on an "AS IS" BASIS, @@ -13,19 +13,17 @@ // limitations under the License. -//#Ulin Project 1718 +//#Ulin Project 17 1819 // /*! -Creation of strings C with zero cost. A plug-in for the rust compiler. +Safe creation of 'CStr' with zero cost at a compilation stage with check of zero bytes and a possibility of communication of several values. # Features -1. The transparent creation of the C strings with zero cost. -2. Check of the C lines at the level of the compiler. -3. Convenient macro for creation of lines. -4. Plug-in for the compiler. - - +1. Creation of safe CStr at a compilation stage. +2. Check of zero bytes at a stage of compilation or checks of "Rls or Rust check". +3. Concatenation of several values, different types: \[u8\], &'static str, u8, i8, (0 without specifying the type). +4. All actions happen at a compilation stage, processor time is not required. # Use ``` @@ -35,120 +33,140 @@ Creation of strings C with zero cost. A plug-in for the rust compiler. use std::ffi::CStr; fn main() { - let c_str = cstr!("cluWorld!!!"); - let c_str_barr = cstr!(b"cluWorld!!!"); - let c_str_b = cstr!(b'A'); -} -``` - -``` -#![feature(plugin)] -#![plugin(clucstr)] - -use std::ffi::CStr; - -fn main() { - println_str(cstr!("cluWorld!!!")); - //CSTR "cluWorld!!!" - //CArray [99, 108, 117, 87, 111, 114, 108, 100, 33, 33, 33, 0] 12 - - println_str(cstr!(b"cluWorld!!!")); - //CSTR "cluWorld!!!" - //CArray [99, 108, 117, 87, 111, 114, 108, 100, 33, 33, 33, 0] 12 - - println_str(cstr!(b'A')); - //CSTR "A" - //CArray [65, 0] 2 + let c_str = cstr!("cluWorld"); + //"cluWorld" <-- [99, 108, 117, 87, 111, 114, 108, 100, 0], len:9 + + let c_str2 = cstr!("cluWorld\0"); + //"cluWorld" <-- [99, 108, 117, 87, 111, 114, 108, 100, 0], len:9 + + let c_str3 = cstr!("clu", b"World"); + //"cluWorld" <-- [99, 108, 117, 87, 111, 114, 108, 100, 0], len:9 + + let c_str4 = cstr!( + b'c', b'l', b'u', + b'W', b'o', b'r', b'l', b'd', + 0 + ); + //"cluWorld" <-- [99, 108, 117, 87, 111, 114, 108, 100, 0], len:9 + + let c_str5 = cstr!( + "clu", + //It is possible to insert such values as: [u8], & 'static str, u8, i8, (0 without specifying the type). + + b'W', b'o', b'r', b'l', b"d\0" + //The zero byte is automatically added, it is possible to write it, and it is possible not to write. + //It is forbidden to insert zero byte in the middle or at the beginning of a line. + ); + //"cluWorld" <-- [99, 108, 117, 87, 111, 114, 108, 100, 0], len:9 + + my_function(c_str); + my_function(c_str2); + my_function(c_str3); + my_function(c_str4); + my_function(c_str5); } - -fn println_str(cstr: &CStr) { - println!("CSTR {:?}", cstr); - - let cstr_array = cstr.to_bytes_with_nul(); - println!("CArray {:?} {}", cstr_array, cstr_array.len()); - println!(); +fn my_function(a: &'static CStr) { + //'static --> it is possible not to write. + + let c_arr = a.to_bytes_with_nul(); + println!("{:?} <-- array: {:?}, len: {}", a, c_arr, c_arr.len()); } ``` # Panic ``` + #![feature(plugin)] #![plugin(clucstr)] +#[allow(unused_imports)] use std::ffi::CStr; fn main() { - let c_str = cstr!("\0Test_str"); - // PANIC! A null byte was found. + //let c_str = cstr!("cluW\0orld"); + //PANIC! trailing byte detected - let c_str = cstr!(b"\0Test_array"); - // PANIC! A null byte was found. + //let c_str2 = cstr!("cluWorld\0\0"); + //PANIC! trailing byte detected - let c_str = cstr!("Test_str\0"); - //It is allowed to write since the null byte is at the end. + //let c_str3 = cstr!("\0clu", b"W\0orld"); + //PANIC! trailing byte detected - let c_str = cstr!(b"Test_str\0"); - //It is allowed to write since the null byte is at the end. + /*let c_str4 = cstr!( + b'c', b'l', b'u', 0u8, + b'W', b'o', b'r', b'l', b'd', + 0 + );*/ + //PANIC! trailing byte detected } ``` # Benchmarking -cstr_macros - old method of converting strings to cstr. Note that in CStr, there is no protection from null bytes. -cstr_plugin - new method for converting strings to cstr. ``` -#![feature(plugin)] -#![plugin(clucstr)] #![feature(test)] -extern crate test; -use std::ffi::CStr; - - -#[macro_export] -macro_rules! cstr_macro { - ($s:expr) => { - unsafe { - ::std::ffi::CStr::from_ptr( - concat!($s, "\0") - as *const str - as *const [::std::os::raw::c_char] - as *const ::std::os::raw::c_char - ) - } - }; -} +#![feature(plugin)] +#![plugin(clucstr)] #[cfg(test)] mod tests { - use super::*; - use test::Bencher; - - #[bench] - fn cstr_plugin(b: &mut Bencher) { - b.iter(|| { - for _a in 0..10 { - let _cstr0 = cstr!(b"test"); - } - }); - } - #[bench] - fn cstr_macros(b: &mut Bencher) { - b.iter(|| { - for _a in 0..10 { - let _cstr0 = cstr_macro!("test"); - } - }); - } + use super::*; + use tests::test::Bencher; + use std::ffi::CStr; + + extern crate test; + + + + macro_rules! unsafe_cstr { + ($s:expr) => { + unsafe { + ::std::ffi::CStr::from_ptr( + concat!($s, "\0") + as *const str + as *const [::std::os::raw::c_char] + as *const ::std::os::raw::c_char + ) + } + }; + } + + #[bench] + fn cstr_plugin(b: &mut Bencher) { + b.iter(|| { + for _a in 0..10 { + let _cstr0 = cstr!(b"test"); + } + }); + } + #[bench] + fn cstr_macros(b: &mut Bencher) { + b.iter(|| { + for _a in 0..10 { + let _cstr0 = unsafe_cstr!("test"); + } + }); + } } ``` running 2 tests -test tests::cstr_macros ... bench: 90 ns/iter (+/- 14) +test tests::cstr_macros ... bench: 67 ns/iter (+/- 1) !Attention ns > 0, full unsafe, no guarantees + +test tests::cstr_plugin ... bench: 0 ns/iter (+/- 0) !Attention ns == 0, plus zero byte checking and plus concatenation + +# Launch benchmark: + +cargo bench --example bench + +# License -test tests::cstr_plugin ... bench: 0 ns/iter (+/- 0) +Copyright 2019 #UlinProject Denis Kotlyarov (Денис Котляров) + +Licensed under the Apache License, Version 2.0 */ @@ -163,3 +181,14 @@ extern crate rustc_plugin; mod nightly; pub use self::nightly::*; + +///Safe creation of 'CStr' at a compilation stage with check on zero bytes and a possibility of concatenation of several values. + +//The description only for documentation not to use. +//Connect a plug-in! (The plug-in is described in nightly.rs, connect a plug-in as it is specified in documentation) +#[macro_export] +macro_rules! cstr { + ($($s:expr),*) => {unimplemented!()}; + ($s:expr) => {unimplemented!()}; + () => {unimplemented!()}; +} diff --git a/src/nightly.rs b/src/nightly.rs new file mode 100644 index 0000000..d757ec5 --- /dev/null +++ b/src/nightly.rs @@ -0,0 +1,227 @@ + +use syntax::source_map::Span; +use syntax::tokenstream::TokenTree; +use syntax::ext::base::{ExtCtxt, MacResult, DummyResult, MacEager}; +use syntax::ext::build::AstBuilder; +use rustc_plugin::Registry; +use syntax::ast::ExprKind; +use syntax::ast::LitKind; +use syntax::ast::Mutability; +use syntax::ast::LitIntType; +use syntax::ast::TyKind; +use syntax::ast::UintTy; +use syntax::ast::UnOp; +use syntax::ast::BlockCheckMode; +use syntax::ast::UnsafeSource; +use syntax::ast::Block; +use syntax::ptr::P; +use syntax::parse::token::Token; +use syntax::ast; +use syntax::ast::IntTy; + + +#[doc(hidden)] +#[plugin_registrar] +pub fn plugin_registrar(reg: &mut Registry) { + reg.register_macro("cstr", cstr); +} + +#[doc(hidden)] +pub fn cstr(cx: &mut ExtCtxt, sp: Span, args: &[TokenTree]) -> Box { + let mut parser = cx.new_parser_from_tts(args); + + let mut args_len = args.len(); + let mut array_expr = Vec::with_capacity(args_len / 2); + if args_len > 0 { + match parser.parse_expr() { + Ok(a) => array_expr.push(a), + Err(_e) => { + cx.span_err(parser.span, "incorrect data, was expected: &[u8], str, u8, i8"); + return DummyResult::any(sp); + } + } + let mut count_elements = 1; + while parser.eat(&Token::Comma) { + args_len -= 1; + //del comma + + match parser.parse_expr() { + Ok(a) => { + count_elements += 1; + array_expr.push(a); + }, + Err(_e) => { + cx.span_err(parser.span, "incorrect data, was expected: &[u8], str, u8, i8"); + return DummyResult::any(sp); + }, + } + } + if count_elements != args_len { + cx.span_err(parser.span, "It was expected ',' or closing of a macro."); + return DummyResult::any(sp); + } + } + + let mut r_array = Vec::with_capacity(args_len * 5); + 'is_add_null: loop { + 'looper: for (unk_index, unk) in array_expr.into_iter().enumerate() { + match unk.node { + ExprKind::Lit(ref l) => { + match l.node { + LitKind::Str(ref array, _) => { + let s_array = array.as_str(); + let array = s_array.as_bytes(); + + for (a_index, a) in array.into_iter().enumerate() { + match a { + 0u8 if unk_index+1 == args_len && a_index+1 == array.len() => break 'looper, + 0u8 => { + cx.span_err(l.span, "trailing byte detected"); + return DummyResult::any(sp); + }, + _ => { + r_array.push( + cx.expr_lit(sp, LitKind::Int(*a as u128, LitIntType::Unsigned(UintTy::U8))) + ); + }, + } + } + }, + LitKind::ByteStr(ref array) => { + let array = array.as_slice(); + + for (a_index, a) in array.into_iter().enumerate() { + match a { + 0u8 if unk_index+1 == args_len && a_index+1 == array.len() => break 'looper, + 0u8 => { + cx.span_err(l.span, "trailing byte detected"); + return DummyResult::any(sp); + }, + _ => { + r_array.push( + cx.expr_lit(sp, LitKind::Int(*a as u128, LitIntType::Unsigned(UintTy::U8))) + ); + }, + } + } + }, + + LitKind::Int(0, LitIntType::Unsuffixed) => { + if unk_index+1 == args_len { + break 'looper; + }else { + cx.span_err(l.span, "trailing byte detected"); + return DummyResult::any(sp); + } + }, + + LitKind::Int(ref a, LitIntType::Unsigned(UintTy::U8)) + | LitKind::Int(ref a, LitIntType::Signed(IntTy::I8)) + => { + match a { + 0u128 if unk_index+1 == args_len => break 'looper, + + 0u128 => { + cx.span_err(l.span, "trailing byte detected"); + return DummyResult::any(sp); + }, + _ => { + r_array.push( + cx.expr_lit(sp, LitKind::Int(*a as u128, LitIntType::Unsigned(UintTy::U8))) + ); + }, + } + }, + + LitKind::Byte(ref a) => { + match a { + 0u8 if unk_index+1 == args_len => break 'looper, + 0u8 => { + cx.span_err(l.span, "trailing byte detected"); + return DummyResult::any(sp); + }, + _ => { + r_array.push( + cx.expr_lit(sp, LitKind::Int(*a as u128, LitIntType::Unsigned(UintTy::U8))) + ); + }, + } + }, + _ => { + cx.span_err(l.span, "incorrect data, was expected: &[u8], str, u8, i8"); + return DummyResult::any(sp); + } + } + }, + _ => { + cx.span_err(unk.span, "incorrect data, was expected: &[u8], str, u8, i8"); + return DummyResult::any(sp); + } + } + } + + r_array.reserve(1); + r_array.push( + cx.expr_lit(sp, LitKind::Int(0u128, LitIntType::Unsigned(UintTy::U8))) + ); + break 'is_add_null; + } + //END ARRAY + + let mut result = cx.expr( + sp, + ExprKind::AddrOf(Mutability::Immutable, + cx.expr(sp, ExprKind::Array(r_array)) //[u8] + //ARRAY EXPR u8 -> EXPR [U8] + ) + );// & [u8] + + result = cx.expr_cast( + sp, + result, //[u8] + cx.ty_ptr(sp, // -> *const [u8] + cx.ty(sp, TyKind::Slice( + cx.ty_ident(sp, cx.ident_of("u8")) + )), // P + + Mutability::Immutable // const + ) + );// &[u8] as *const [u8] + + result = cx.expr_cast( + sp, + result, //[i8] + cx.ty_ptr(sp, // -> *const [i8] + cx.ty_ident(sp, cx.ident_of("CStr")), + + Mutability::Immutable // const + ) + ); // as *const CSTR + + result = cx.expr_unary(sp, UnOp::Deref, result); + //* ([u8] as *const [u8] as *const CStr) + + result = cx.expr(sp, ExprKind::AddrOf(Mutability::Immutable, result)); + //& *([u8] as *const [u8] as *const CStr) + + MacEager::expr({ + let block = P(Block { + stmts: { //{block} + let mut r = Vec::with_capacity(1); + r.push( + cx.stmt_expr(result) //ADD EXPR TO BLOCK + ); + r + }, + id: ast::DUMMY_NODE_ID, + rules: BlockCheckMode::Unsafe(UnsafeSource::CompilerGenerated), //<-- UNSAFE + span: sp, + + //recovered: false, + //FIX!, UPDATE RUST:(( + }); + cx.expr_block(block) //RESULT EXPR + })// unsafe { &*([u8] as *const [u8] as *const CStr) } +} + + diff --git a/src/nightly/mod.rs b/src/nightly/mod.rs deleted file mode 100644 index 56c8845..0000000 --- a/src/nightly/mod.rs +++ /dev/null @@ -1,187 +0,0 @@ - -use syntax::tokenstream::TokenTree; -use syntax::ext::base::{ExtCtxt, MacResult, DummyResult, MacEager}; -use syntax::ext::build::AstBuilder; -use syntax::ext::quote::rt::Span; -use rustc_plugin::Registry; -use syntax::ast::ExprKind; -use syntax::ast::LitKind; -use syntax::ast::Mutability; -use syntax::ast::LitIntType; -use syntax::ast::TyKind; -use syntax::ast::UintTy; -use syntax::ast::UnOp; -use syntax::ast::BlockCheckMode; -use syntax::ast::UnsafeSource; -use syntax::ast::Block; -use syntax::ptr::P; -use syntax::ast; - -///Safe creation of CStr with zero cost -//It is required for documentation! -#[macro_export] -macro_rules! cstr { - ($s:expr) => {}; -} -//It is required for documentation! - - -#[doc(hidden)] -#[plugin_registrar] -pub fn plugin_registrar(reg: &mut Registry) { - reg.register_macro("cstr", cstr); -} - -#[doc(hidden)] -pub fn cstr(cx: &mut ExtCtxt, sp: Span, args: &[TokenTree]) -> Box { - let mut parser = cx.new_parser_from_tts(args); - - let expr = match parser.parse_expr() { - Ok(a) => a, - Err(_e) => { - cx.span_err(sp, "cstr only supports now one parameter"); - return DummyResult::any(sp); - } - }; - - let c_array = { - let mut add_null = true; - - let mut array = match expr.node { - ExprKind::Lit(ref l) => { - match l.node { - LitKind::Str(s, _) => { - let s = s.to_string(); - let array = s.as_bytes(); - let array_len = array.len(); - - let mut vec_result = Vec::with_capacity(array_len); - - for (num, a) in array.iter().enumerate() { - if *a == 0 { - match num+1 == array_len { - true => add_null = false, - _ => { - cx.span_err(sp, "in line not admissible characters are found."); - return DummyResult::any(sp); - }, - } - } - vec_result.push( - cx.expr_lit(sp, - LitKind::Int(*a as u128, LitIntType::Unsigned(UintTy::U8)), - ) - ); - } - vec_result - }, - LitKind::ByteStr(ref array) => { - let array_len = array.len(); - let mut vec_result = Vec::with_capacity(array.len()); - - for (num, a) in array.iter().enumerate() { - if *a == 0 { - match num+1 == array_len { - true => add_null = false, - _ => { - cx.span_err(sp, "in line not admissible characters are found."); - return DummyResult::any(sp); - }, - } - } - vec_result.push( - cx.expr_lit(sp, - LitKind::Int(*a as u128, LitIntType::Unsigned(UintTy::U8)), - ) - ); - } - vec_result - }, - LitKind::Byte(ref a) => { - if *a == 0 { - add_null = false; - } - vec!( - cx.expr_lit(sp, - LitKind::Int(*a as u128, LitIntType::Unsigned(UintTy::U8)), - ) - ) - } - _ => { - cx.span_err(sp, "not incorrect data are transferred to a macro"); - return DummyResult::any(sp); - } - - } - }, - _ => { - cx.span_err(sp, "not incorrect data are transferred to a macro"); - return DummyResult::any(sp); - } - }; - - if add_null { - array.reserve(1); - array.push( - cx.expr_lit(sp, - LitKind::Int(0, LitIntType::Unsigned(UintTy::U8)), - ) - ); - } - - cx.expr( - sp, - ExprKind::AddrOf(Mutability::Immutable, - cx.expr(sp, ExprKind::Array(array)) //[u8] - ) // &[u8] - ) - }; - - let c_array = cx.expr_cast( - sp, - c_array, //[u8] - cx.ty_ptr(sp, // -> *const [u8] - cx.ty(sp, TyKind::Slice( - cx.ty_ident(sp, cx.ident_of("u8")) - )), // P - - Mutability::Immutable // const - ) - );// &[u8] as *const [u8] - - let c_cstr = cx.expr_cast( - sp, - c_array, //[i8] - cx.ty_ptr(sp, // -> *const [i8] - cx.ty_ident(sp, cx.ident_of("CStr")), - - Mutability::Immutable // const - ) - ); // as *const CSTR - - let c_cstr = cx.expr_unary(sp, UnOp::Deref, c_cstr); - //*([u8] as *const [u8] as *const CStr) - - let c_cstr = cx.expr(sp, ExprKind::AddrOf(Mutability::Immutable, c_cstr)); - //&*([u8] as *const [u8] as *const CStr) - - let block = { - let vec_stmts = vec!( - cx.stmt_expr(c_cstr) - ); - let mut block = P(Block { - stmts: vec_stmts, - id: ast::DUMMY_NODE_ID, - rules: BlockCheckMode::Unsafe(UnsafeSource::CompilerGenerated), - span: sp, - recovered: false, - - }); - cx.expr_block(block) - };// unsafe { &*([u8] as *const [u8] as *const CStr) } - - - MacEager::expr( - block - ) -}