@@ -102,6 +102,75 @@ impl<const N: usize, LenT: LenType> CString<N, LenT> {
102102 Ok ( string)
103103 }
104104
105+ /// Instantiates a [`CString`] copying from the given byte slice, until the first nul character.
106+ /// `bytes` may contain any number of nul characters, or none at all.
107+ ///
108+ /// This method mimics [`CStr::from_bytes_until_nul`] with two important differences:
109+ /// [`Self::from_bytes_truncating_at_nul`] copies the data, and it does not fail on
110+ /// non-nul terminated data.
111+ ///
112+ /// Fails if the given byte slice can't fit in `N`.
113+ ///
114+ /// # Examples
115+ /// You can pass a byte array with one, many, or no nul bytes as `bytes`.
116+ ///
117+ /// ```rust
118+ /// use heapless::CString;
119+ ///
120+ /// let c_string = CString::<11>::from_bytes_truncating_at_nul(b"hey there!\0").unwrap();
121+ /// assert_eq!(c_string.as_c_str(), c"hey there!");
122+ ///
123+ /// let c_string = CString::<11>::from_bytes_truncating_at_nul(b"hey\0there\0!").unwrap();
124+ /// assert_eq!(c_string.as_c_str(), c"hey");
125+ ///
126+ /// let c_string = CString::<11>::from_bytes_truncating_at_nul(b"hey there!").unwrap();
127+ /// assert_eq!(c_string.as_c_str(), c"hey there!");
128+ /// ```
129+ ///
130+ /// If `bytes` is too long, an error is returned.
131+ /// ```rust
132+ /// use heapless::CString;
133+ ///
134+ /// assert!(CString::<3>::from_bytes_truncating_at_nul(b"hey\0").is_err());
135+ /// ```
136+ ///
137+ /// `bytes` may also represent an empty string.
138+ /// ```rust
139+ /// use heapless::CString;
140+ ///
141+ /// assert_eq!(CString::<1>::from_bytes_truncating_at_nul(b"").unwrap().as_c_str(), c"");
142+ /// assert_eq!(CString::<1>::from_bytes_truncating_at_nul(b"\0").unwrap().as_c_str(), c"");
143+ /// ```
144+ pub fn from_bytes_truncating_at_nul ( bytes : & [ u8 ] ) -> Result < Self , ExtendError > {
145+ // Truncate `bytes` to before the first nul byte.
146+ // `bytes` will not contain any nul bytes.
147+ let bytes = match CStr :: from_bytes_with_nul ( bytes) {
148+ Ok ( _) => & bytes[ ..bytes. len ( ) - 1 ] , // bytes.len() > 0, as `bytes` is nul-terminated
149+ Err ( FromBytesWithNulError :: InteriorNul { position } ) => & bytes[ ..position] ,
150+ Err ( FromBytesWithNulError :: NotNulTerminated ) => bytes,
151+ } ;
152+
153+ let mut string = Self :: new ( ) ;
154+ if let Some ( capacity) = string. capacity_with_bytes ( bytes) {
155+ // Cannot store `bytes` due to insufficient capacity.
156+ if capacity > N {
157+ return Err ( CapacityError . into ( ) ) ;
158+ }
159+ }
160+
161+ // SAFETY:
162+ // `string` is left in a valid state because
163+ // the appended bytes do not contain any nul bytes,
164+ // and we push a nul byte at the end.
165+ //
166+ // We've ensured above that there is enough space to push `bytes`
167+ // and the nul byte.
168+ unsafe { string. extend_from_bytes_unchecked ( bytes) } ?;
169+ unsafe { string. inner . push_unchecked ( 0 ) } ;
170+
171+ Ok ( string)
172+ }
173+
105174 /// Builds a [`CString`] copying from a raw C string pointer.
106175 ///
107176 /// # Safety
0 commit comments