1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155
// Copyright © 2017 Trevor Spiteri // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or // https://www.apache.org/licenses/LICENSE-2.0> or the MIT license // <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your // option. This file may not be copied, modified, or distributed // except according to those terms. //! # String concatenation //! //! Concatenatation of characters ([`char`][char]), string slices //! ([`&str`][str]) and owned strings ([`String`][String]). //! //! A concatenation is started with the [`Cat`][Cat] element, and any //! number of characters, string slices or strings can be concatenated //! using the `+` operator. The concatenation can be converted or //! appended to a `String`. //! //! If the concatenation is converted to a `String`, and it starts //! with an owned string with enough capacity to store the result, no //! allocations or reallocations take place. If the concatenation is //! appended to a `String` with enough capacity, no allocations or //! reallocations take place. Otherwise, one allocation or //! reallocation takes place. //! //! ## Examples //! //! A concatenation can be converted to a `String`. //! //! ```rust //! use sconcat::Cat; //! //! let cat1 = Cat + "Hello, " + "world! " + '☺'; //! // One allocation: //! let s1 = String::from(cat1); //! assert_eq!(s1, "Hello, world! ☺"); //! //! let cat2 = Cat + String::from("Hello, ") + "world! " + '☺'; //! // At most one reallocation as the initial `String` is resized: //! let s2 = String::from(cat2); //! assert_eq!(s2, "Hello, world! ☺"); //! ``` //! //! A concatenation can also be appended to a `String`. //! //! ```rust //! use sconcat::Cat; //! //! let cat = Cat + "world! " + '☺'; //! let mut s = String::from("Hello, "); //! // At most one reallocation as the initial `s` is resized: //! s += cat; //! assert_eq!(s, "Hello, world! ☺"); //! ``` //! //! If the concatenation starts with a `String` that has enough //! reserved space, no reallocations will take place. //! //! ```rust //! use sconcat::Cat; //! //! let mut buf = String::from("Hello, "); //! // 7 bytes for "world! " and 3 bytes for '☺' //! buf.reserve(10); //! let ptr = buf.as_ptr(); //! let cat = Cat + buf + "world! " + '☺'; //! let s2 = String::from(cat); //! assert_eq!(s2, "Hello, world! ☺"); //! assert_eq!(s2.as_ptr(), ptr); //! ``` //! //! The concatenation also implements [`Display`][Display] and //! [`Debug`][Debug]. However, using `to_string()` can result in //! multiple reallocations, so `String::from(cat)` is preferred over //! `cat.to_string()` where possible. //! //! ```rust //! use sconcat::Cat; //! //! let cat = Cat + "Hello, " + "world! " + '☺'; //! // `s1` can be resized up to three times: //! let s1 = cat.to_string(); //! assert_eq!(s1, "Hello, world! ☺"); //! // Only one allocation here: //! let s2 = String::from(cat); //! assert_eq!(s2, "Hello, world! ☺"); //! // The following would fail as now `cat` has been moved: //! // let s3 = String::from(cat); //! ``` //! //! ## Usage //! //! To use `sconcat` in your crate, add `extern crate sconcat;` to the //! crate root and add `sconcat` as a dependency in `Cargo.toml`: //! //! ```toml //! [dependencies] //! sconcat = "0.2" //! ``` //! //! ### Optional features //! //! The crate supports an optional feature `fast_fmt`, which adds a //! dependency on the [`fast_fmt`][fastfmt] crate. When the feature is //! enabled, the concatenation implements `fast_fmt::Fmt`. To enable //! the feature, the dependency in `Cargo.toml` can be added as: //! //! ```toml //! [dependencies] //! sconcat = { version = "0.2", features = ["fast_fmt"] } //! ``` //! //! [Cat]: struct.Cat.html //! [Debug]: https://doc.rust-lang.org/std/fmt/trait.Debug.html //! [Display]: https://doc.rust-lang.org/std/fmt/trait.Display.html //! [fastfmt]: https://crates.io/crates/fast_fmt //! [String]: https://doc.rust-lang.org/std/string/struct.String.html //! [char]: https://doc.rust-lang.org/std/primitive.char.html //! [str]: https://doc.rust-lang.org/std/primitive.str.html #![warn(missing_docs)] #![doc(html_root_url = "https://docs.rs/sconcat/0.2.1/", test(attr(deny(warnings))))] #[cfg(feature = "fast_fmt")] extern crate fast_fmt; mod cat; pub use cat::Cat; #[cfg(test)] mod tests { use Cat; #[test] fn readme_example_works() { let cat1 = Cat + "Hello, " + "world! " + '☺'; let s1 = String::from(cat1); assert_eq!(s1, "Hello, world! ☺"); let mut s2 = String::from("Hello"); s2 += Cat + ',' + " world" + String::from("! ") + '☺'; assert_eq!(s2, "Hello, world! ☺"); let mut buf = String::from("Hello, "); // 7 bytes for "world! " and 3 bytes for '☺' buf.reserve(10); let ptr = buf.as_ptr(); // buf is large enough, so no reallocations take place let cat3 = Cat + buf + "world! " + '☺'; let s3 = String::from(cat3); assert_eq!(s3, "Hello, world! ☺"); assert_eq!(s3.as_ptr(), ptr); } }