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
//! Provides efficient concatenation of strings and vectors //! //! The goal of these macros are to reduce the amount of allocations that are required //! when concatenating string buffers and vectors; with a macro that makes it simple to //! achieve in practice. //! //! # Implementation Notes //! //! - The caller must provide a buffer for appending the slices to //! - The buffer is resized to accomodate the total length of all slices given /// Appends any number of string slices onto a string buffer /// /// ```rust /// use concat_in_place::strcat; /// /// let domain = "domain.com"; /// let endpoint = "inventory/parts"; /// let id = "10512"; /// /// let mut url = String::new(); /// let slice = strcat!(&mut url, domain "/" endpoint "/" id); /// assert_eq!(slice, "domain.com/inventory/parts/10512"); /// ``` /// /// # Implementation Notes /// /// Technically works with any string type that has the following methods: /// /// - `capacity` /// - `len` /// - `push_str` #[macro_export] macro_rules! strcat { ($input:expr, $($element:expr)*) => {{ let out = $input; let mut required = 0; $( required += $element.len(); )* let free = out.capacity() - out.len(); if (free < required) { out.reserve(required - free); } $( out.push_str($element); )* &*out }} } /// Appends any number of slices onto a vector /// /// ```rust /// use concat_in_place::veccat; /// /// let domain = b"domain.com"; /// let endpoint = b"inventory/parts"; /// let id = b"10512"; /// /// let mut url = Vec::new(); /// let slice = veccat!(&mut url, domain b"/" endpoint b"/" id); /// assert_eq!(slice, b"domain.com/inventory/parts/10512"); /// ``` /// /// # Implementation Notes /// /// Technically works with any type that has the following methods: /// /// - `capacity` /// - `len` /// - `reserve` /// - `extend_from_slice` #[macro_export] macro_rules! veccat { ($input:expr, $($element:expr)*) => {{ let out = $input; let mut required = 0; $( required += $element.len(); )* let free = out.capacity() - out.len(); if (free < required) { out.reserve(required - free); } $( out.extend_from_slice($element); )* &*out }} } #[cfg(test)] mod tests { use super::*; #[test] fn bytes() { let mut out = Vec::new(); let expected = b"domain.com/endpoint/id"; let actual: &[u8] = veccat!(&mut out, b"domain.com" b"/" b"endpoint" b"/" b"id"); assert_eq!(actual, expected, "{}", String::from_utf8_lossy(actual)); } #[test] fn strings() { let mut out = String::new(); let expected = "domain.com/endpoint/id"; let actual = strcat!(&mut out, "domain.com" "/" "endpoint" "/" "id"); assert_eq!(actual, expected); } }