typed_ident/alloc/fragment.rs
1// =============================================================================
2// USES
3// =============================================================================
4
5// -----------------------------------------------------------------------------
6use crate::core::error::{Error, ErrorKind};
7use crate::syntax::{Boundary, Delimiter, Profile};
8use crate::{Fragment, FragmentBuf};
9use std_alloc::boxed::Box;
10use std_alloc::string::String;
11
12// =============================================================================
13// IMPLS
14// =============================================================================
15
16// -----------------------------------------------------------------------------
17impl<B: Boundary, D: Delimiter, P: Profile> Fragment<B, D, P> {
18 /// Returns a heap-allocated fragment, joined with the original fragment in
19 /// a way that preserves chunk boundaries.
20 ///
21 /// At the end of the operation, the total number of chunked segments
22 /// present in the fragment will be equal to the sum of each fragment,
23 /// potentially plus one additional fragment in the case where we needed to
24 /// join using a delimiter to preserve chunk boundaries.
25 ///
26 /// This call is identical to [`join_with`] with the default delimiter.
27 ///
28 /// It can be a bit cumbersome to use this function in most cases. Instead,
29 /// if you find it easier to work with string data (or you don't have any
30 /// fragments that you're joining with), you can use [`join_str`].
31 ///
32 /// [`join_str`]: Self::join_str
33 /// [`join_with`]: Self::join_with
34 ///
35 /// # Errors
36 ///
37 /// Returns `Err` if the fragment formed from the combination of `self` and
38 /// `fragment` is invalid. If invalid, an [`Error`] is returned with the
39 /// [`error_kind`] set to `FailedJoinLeft`.
40 ///
41 /// The value [`byte_offset`] will *NOT* be set from this function. None of
42 /// the individual characters are invalid, it's just that the combination of
43 /// joining the fragments themselves is invalid.
44 ///
45 /// [`Error`]: crate::Error
46 /// [`error_kind`]: crate::Error::error_kind
47 /// [`byte_offset`]: crate::Error::byte_offset
48 ///
49 /// # Examples
50 ///
51 /// Basic Usage:
52 ///
53 /// ```
54 /// # use typed_ident::presets::unicode::lower_snake::*;
55 /// let fragment = LowerSnakeFragment::new("snake")?;
56 /// let fragment = fragment.join(
57 /// LowerSnakeFragment::new("fragment")?,
58 /// )?;
59 /// assert_eq!(fragment, "snake_fragment");
60 /// # Ok::<(), typed_ident::Error>(())
61 /// ```
62 #[must_use = "this function returns an allocated fragment, it does not mutate the original"]
63 #[inline]
64 pub fn join(&self, fragment: &Fragment<B, D, P>) -> Result<FragmentBuf<B, D, P>, Error>
65 where
66 D: Default,
67 {
68 self.join_with(fragment, D::default())
69 }
70
71 /// Returns a heap-allocated fragment, joined with the original fragment in
72 /// a way that preserves chunk boundaries. The provided string is first
73 /// converted to a fragment before attempting to append it.
74 ///
75 /// At the end of the operation, the total number of chunked segments
76 /// present in the fragment will be equal to the sum of each fragment,
77 /// potentially plus one additional fragment in the case where we needed to
78 /// join using a delimiter to preserve chunk boundaries.
79 ///
80 /// This call is identical to [`join_str_with`] with the default delimiter.
81 ///
82 /// [`join_str_with`]: Self::join_str_with
83 ///
84 /// # Errors
85 ///
86 /// Returns `Err` if the fragment formed from the combination of `self` and
87 /// `fragment` is invalid. If invalid, an [`Error`] is returned with the
88 /// [`error_kind`] set to `FailedJoinLeft`.
89 ///
90 /// The value [`byte_offset`] *MAY* be set on this function. If the joining
91 /// string contained invalid characters, this will be set to the byte index
92 /// (from the start of the joining string) that was invalid.
93 ///
94 /// However, if all characters are independently valid, but one side failed
95 /// to join (because the join itself would make the following character
96 /// invalid), then `byte_offset` will be set to `None`.
97 ///
98 /// [`Error`]: crate::Error
99 /// [`error_kind`]: crate::Error::error_kind
100 /// [`byte_offset`]: crate::Error::byte_offset
101 ///
102 /// # Examples
103 ///
104 /// Basic Usage:
105 ///
106 /// ```
107 /// # use typed_ident::presets::unicode::lower_snake::*;
108 /// let fragment = LowerSnakeFragment::new("snake")?;
109 /// let fragment = fragment.join_str("fragment")?;
110 /// assert_eq!(fragment, "snake_fragment");
111 /// # Ok::<(), typed_ident::Error>(())
112 /// ```
113 #[must_use = "this function returns an allocated fragment, it does not mutate the original"]
114 #[inline]
115 pub fn join_str(&self, s: &str) -> Result<FragmentBuf<B, D, P>, Error>
116 where
117 D: Default,
118 {
119 self.join_str_with(s, D::default())
120 }
121
122 /// Returns a heap-allocated fragment, joined with the original fragment in
123 /// a way that preserves chunk boundaries. The provided string is first
124 /// converted to a fragment before attempting to append it.
125 ///
126 /// At the end of the operation, the total number of chunked segments
127 /// present in the fragment will be equal to the sum of each fragment,
128 /// potentially plus one additional fragment in the case where we needed to
129 /// join using a delimiter to preserve chunk boundaries.
130 ///
131 /// # Errors
132 ///
133 /// Returns `Err` if the fragment formed from the combination of `self` and
134 /// `fragment` is invalid. If invalid, an [`Error`] is returned with the
135 /// [`error_kind`] set to `InvalidFormat` or `FailedJoinLeft`.
136 ///
137 /// The value [`byte_offset`] *MAY* be set on this function. If the joining
138 /// string contained invalid characters, this will be set to the byte index
139 /// (from the start of the joining string) that was invalid.
140 ///
141 /// However, if all characters are independently valid, but one side failed
142 /// to join (because the join itself would make the following character
143 /// invalid), then `byte_offset` will be set to `None`.
144 ///
145 /// [`Error`]: crate::Error
146 /// [`error_kind`]: crate::Error::error_kind
147 /// [`byte_offset`]: crate::Error::byte_offset
148 ///
149 /// # Examples
150 ///
151 /// Basic Usage:
152 ///
153 /// ```
154 /// # use typed_ident::syntax::delimiter::LowLine;
155 /// # use typed_ident::presets::unicode::lower_snake::*;
156 /// let fragment = LowerSnakeFragment::new("snake")?;
157 /// let fragment = fragment.join_str_with("fragment", LowLine)?;
158 /// assert_eq!(fragment, "snake_fragment");
159 /// # Ok::<(), typed_ident::Error>(())
160 /// ```
161 #[must_use = "this function returns an allocated fragment, it does not mutate the original"]
162 #[inline]
163 pub fn join_str_with(&self, s: &str, delim: D) -> Result<FragmentBuf<B, D, P>, Error> {
164 let fragment = Fragment::new(s)?;
165 self.join_with(fragment, delim)
166 }
167
168 /// Returns a heap-allocated fragment, joined with the original fragment in
169 /// a way that preserves chunk boundaries.
170 ///
171 /// At the end of the operation, the total number of chunked segments
172 /// present in the fragment will be equal to the sum of each fragment,
173 /// potentially plus one additional fragment in the case where we needed to
174 /// join using a delimiter to preserve chunk boundaries.
175 ///
176 /// It can be a bit cumbersome to use this function in most cases. Instead,
177 /// if you find it easier to work with string data (or you don't have any
178 /// fragments that you're joining with), you can use [`join_str_with`].
179 ///
180 /// [`join_str_with`]: Self::join_str_with
181 ///
182 /// # Errors
183 ///
184 /// Returns `Err` if the fragment formed from the combination of `self` and
185 /// `fragment` is invalid. If invalid, an [`Error`] is returned with the
186 /// [`error_kind`] set to `FailedJoinLeft`.
187 ///
188 /// The value [`byte_offset`] will *NOT* be set from this function. None of
189 /// the individual characters are invalid, it's just that the combination of
190 /// joining the fragments themselves is invalid.
191 ///
192 /// [`Error`]: crate::Error
193 /// [`error_kind`]: crate::Error::error_kind
194 /// [`byte_offset`]: crate::Error::byte_offset
195 ///
196 /// # Examples
197 ///
198 /// Basic Usage:
199 ///
200 /// ```
201 /// # use typed_ident::syntax::delimiter::LowLine;
202 /// # use typed_ident::presets::unicode::lower_snake::*;
203 /// let fragment = LowerSnakeFragment::new("snake")?;
204 /// let fragment = fragment.join_with(
205 /// LowerSnakeFragment::new("fragment")?,
206 /// LowLine,
207 /// )?;
208 /// assert_eq!(fragment, "snake_fragment");
209 /// # Ok::<(), typed_ident::Error>(())
210 /// ```
211 #[must_use = "this function returns an allocated fragment, it does not mutate the original"]
212 #[inline]
213 pub fn join_with(
214 &self,
215 fragment: &Fragment<B, D, P>,
216 delim: D,
217 ) -> Result<FragmentBuf<B, D, P>, Error> {
218 let mut buffer = FragmentBuf::with_overhead(self, fragment.len() + 1);
219 buffer.push_bounded_fragment_with(fragment, delim)?;
220 Ok(buffer)
221 }
222
223 /// Converts a string into a boxed identifier if its valid.
224 ///
225 /// # Examples
226 ///
227 /// Basic Usage:
228 ///
229 /// ```
230 /// # use typed_ident::*;
231 /// # use typed_ident::presets::unicode::lower_snake::*;
232 /// let fragment: Box<LowerSnakeFragment> =
233 /// Fragment::new_boxed(String::from("snake_fragment"))?;
234 /// # Ok::<(), typed_ident::Error>(())
235 /// ```
236 #[inline]
237 pub fn new_boxed(string: String) -> Result<Box<Fragment<B, D, P>>, Error> {
238 let _ = Fragment::<B, D, P>::new(&string)?;
239 Ok(Self::new_boxed_unchecked(string))
240 }
241
242 /// Returns a heap-allocated fragment, replacing the provided pattern with
243 /// a fragment of the user's choice.
244 ///
245 /// It can be a bit cumbersome to use this function in most cases. Instead,
246 /// if you find it easier to work with string data (or you don't have any
247 /// fragments that you're replacing with), you can use [`replace_str`].
248 ///
249 /// [`replace_str`]: Self::replace_str
250 ///
251 /// # Errors
252 ///
253 /// Returns `Err` if the fragment formed from the combination of `self` and
254 /// `to` is invalid at any replacement index. If invalid, an [`Error`] is
255 /// returned with the [`error_kind`] set to either `FailedReplaceLeft` (if
256 /// `to` was invalid at a specific replacement) or `FailedReplaceRight` (if
257 /// `to` was valid, but the remainder was not valid after `to`).
258 ///
259 /// The value [`byte_offset`] *WILL* be set from this function, and it will
260 /// be set to the index that caused the failure from the original fragment
261 /// (`self`).
262 ///
263 /// So for `FailedReplaceLeft`, this is the byte index of the replacement.
264 /// For `FailedReplaceRight`, this is the byte index of the residual that
265 /// failed to join with the replacement.
266 ///
267 /// [`Error`]: crate::Error
268 /// [`error_kind`]: crate::Error::error_kind
269 /// [`byte_offset`]: crate::Error::byte_offset
270 ///
271 /// # Examples
272 ///
273 /// Basic Usage:
274 ///
275 /// ```
276 /// # use typed_ident::syntax::delimiter::LowLine;
277 /// # use typed_ident::presets::unicode::lower_snake::*;
278 /// let fragment = LowerSnakeFragment::new("example_snake_identifier")?;
279 /// let fragment = fragment.replace(
280 /// "snake",
281 /// LowerSnakeFragment::new("serpent")?,
282 /// )?;
283 /// assert_eq!(fragment, "example_serpent_identifier");
284 /// # Ok::<(), typed_ident::Error>(())
285 /// ```
286 #[must_use = "this function returns an allocated fragment, it does not mutate the original"]
287 #[inline]
288 pub fn replace<M>(&self, from: M, to: &Fragment<B, D, P>) -> Result<FragmentBuf<B, D, P>, Error>
289 where
290 M: crate::core::pattern::Pattern,
291 {
292 let mut buffer = FragmentBuf::with_capacity(self.len());
293 let mut last_end = 0;
294 for (start, part) in self.match_indices(from) {
295 buffer.push_fragment(&self[last_end..start]).map_err(|_| {
296 Error::new(ErrorKind::FailedReplaceRight).with_byte_offset(last_end)
297 })?;
298 buffer
299 .push_fragment(to)
300 .map_err(|_| Error::new(ErrorKind::FailedReplaceLeft).with_byte_offset(start))?;
301 last_end = start + part.len();
302 }
303 buffer
304 .push_fragment(&self[last_end..self.len()])
305 .map_err(|_| Error::new(ErrorKind::FailedReplaceRight).with_byte_offset(last_end))?;
306 Ok(buffer)
307 }
308
309 /// Returns a heap-allocated fragment, replacing the provided pattern with
310 /// a fragment of the user's choice. The provided string is first converted
311 /// to a fragment before attempting to append it.
312 ///
313 /// It can be a bit cumbersome to use this function in most cases. Instead,
314 /// if you find it easier to work with string data (or you don't have any
315 /// fragments that you're replacing with), you can use [`replace_str`].
316 ///
317 /// [`replace_str`]: Self::replace_str
318 ///
319 /// # Errors
320 ///
321 /// Returns `Err` if the fragment formed from the combination of `self` and
322 /// `to` is invalid at any replacement index. If invalid, an [`Error`] is
323 /// returned with the [`error_kind`] set to `InvalidFormat` if the
324 /// provided fragment was invalid, or `InvalidReplace` if the replacement
325 /// failed.
326 ///
327 /// The value [`byte_offset`] *WILL* be set from this function. On invalid
328 /// fragment, it will be set to the byte index from the start of the
329 /// fragment which was invalid. On invalid replacement, it will be set to
330 /// the byte index that caused the failure from the original fragment
331 /// (`self`).
332 ///
333 /// [`Error`]: crate::Error
334 /// [`error_kind`]: crate::Error::error_kind
335 /// [`byte_offset`]: crate::Error::byte_offset
336 ///
337 /// # Examples
338 ///
339 /// Basic Usage:
340 ///
341 /// ```
342 /// # use typed_ident::syntax::delimiter::LowLine;
343 /// # use typed_ident::presets::unicode::lower_snake::*;
344 /// let fragment = LowerSnakeFragment::new("example_snake_identifier")?;
345 /// let fragment = fragment.replace_str("snake", "serpent")?;
346 /// assert_eq!(fragment, "example_serpent_identifier");
347 /// # Ok::<(), typed_ident::Error>(())
348 /// ```
349 #[must_use = "this function returns an allocated fragment, it does not mutate the original"]
350 #[inline]
351 pub fn replace_str<M>(&self, from: M, to: &str) -> Result<FragmentBuf<B, D, P>, Error>
352 where
353 M: crate::core::pattern::Pattern,
354 {
355 self.replace(from, Fragment::new(to)?)
356 }
357
358 /// Returns a heap-allocated fragment with the provided prefix and suffix
359 /// attached to the original fragment.
360 ///
361 /// It can be a bit cumbersome to use this function in most cases. Instead,
362 /// if you find it easier to work with string data (or you don't have any
363 /// fragments that you're joining with), you can use [`with_circumfix_str`].
364 ///
365 /// [`with_circumfix_str`]: Self::with_circumfix_str
366 ///
367 /// # Errors
368 ///
369 /// Returns `Err` if the fragment formed from the combination of `prefix`,
370 /// `self`, and `suffix` is invalid. If invalid, an [`Error`] is returned
371 /// with the [`error_kind`] set either to `FailedJoinLeft` or
372 /// `FailedJoinRight` (depending on which side caused the failure).
373 ///
374 /// The value [`byte_offset`] will *NOT* be set from this function. None of
375 /// the individual characters are invalid, it's just that the combination of
376 /// joining the fragments themselves is invalid.
377 ///
378 /// [`Error`]: crate::Error
379 /// [`error_kind`]: crate::Error::error_kind
380 /// [`byte_offset`]: crate::Error::byte_offset
381 ///
382 /// # Examples
383 ///
384 /// Basic Usage:
385 ///
386 /// ```
387 /// # use typed_ident::presets::unicode::lower_snake::*;
388 /// let fragment = LowerSnakeFragment::new("snake")?;
389 /// let fragment = fragment.with_circumfix(
390 /// LowerSnakeFragment::new("lower_")?,
391 /// LowerSnakeFragment::new("_fragment")?,
392 /// )?;
393 /// assert_eq!(fragment, "lower_snake_fragment");
394 /// # Ok::<(), typed_ident::Error>(())
395 /// ```
396 #[must_use = "this function returns an allocated fragment, it does not mutate the original"]
397 #[inline]
398 pub fn with_circumfix(
399 &self,
400 prefix: &Fragment<B, D, P>,
401 suffix: &Fragment<B, D, P>,
402 ) -> Result<FragmentBuf<B, D, P>, Error> {
403 let mut buffer = FragmentBuf::with_overhead(prefix, self.len() + suffix.len());
404 buffer.push_fragment(self)?;
405 buffer
406 .push_fragment(suffix)
407 .map_err(|_| Error::new(ErrorKind::FailedJoinRight))?;
408 Ok(buffer)
409 }
410
411 /// Returns a heap-allocated fragment with the provided prefix and suffix
412 /// strings attached to the original fragment. The provided strings are
413 /// first converted to fragments before attempting to append them.
414 ///
415 /// # Errors
416 ///
417 /// Returns `Err` if the either of the provided fragments are invalid.
418 /// If one of them is invalid, an [`Error`] is returned with the
419 /// [`error_kind`] set to `InvalidPrefix` or `InvalidSuffix` depending on
420 /// which was invalid (prefix takes precedence if both are invalid).
421 ///
422 /// Returns `Err` if the fragment formed from the combination of `prefix`,
423 /// `self`, and `suffix` is invalid. If invalid, an [`Error`] is returned
424 /// with the [`error_kind`] set either to `FailedJoinLeft` or
425 /// `FailedJoinRight` (depending on which side caused the failure).
426 ///
427 /// The value [`byte_offset`] *MAY* be set on this function. If the prefix
428 /// or suffix strings contained invalid characters, this will be set to the
429 /// byte index (from the start of either the prefix or suffix, depending on
430 /// which `error_kind` was set) that was invalid.
431 ///
432 /// However, if all characters are independently valid, but one side failed
433 /// to join (because the join itself would make the following character
434 /// invalid), then `byte_offset` will be set to `None`.
435 ///
436 /// [`Error`]: crate::Error
437 /// [`error_kind`]: crate::Error::error_kind
438 /// [`byte_offset`]: crate::Error::byte_offset
439 ///
440 /// # Examples
441 ///
442 /// Basic Usage:
443 ///
444 /// ```
445 /// # use typed_ident::presets::unicode::lower_snake::*;
446 /// let fragment = LowerSnakeFragment::new("snake")?;
447 /// let fragment = fragment.with_circumfix_str("lower_", "_fragment")?;
448 /// assert_eq!(fragment, "lower_snake_fragment");
449 /// # Ok::<(), typed_ident::Error>(())
450 /// ```
451 #[must_use = "this function returns an allocated fragment, it does not mutate the original"]
452 #[inline]
453 pub fn with_circumfix_str(
454 &self,
455 prefix: &str,
456 suffix: &str,
457 ) -> Result<FragmentBuf<B, D, P>, Error> {
458 let prefix =
459 Fragment::new(prefix).map_err(|e| e.with_error_kind(ErrorKind::InvalidPrefix))?;
460 let suffix =
461 Fragment::new(suffix).map_err(|e| e.with_error_kind(ErrorKind::InvalidSuffix))?;
462 self.with_circumfix(prefix, suffix)
463 }
464
465 /// Returns a heap-allocated fragment with the provided prefix attached to
466 /// the original fragment.
467 ///
468 /// It can be a bit cumbersome to use this function in most cases. Instead,
469 /// if you find it easier to work with string data (or you don't have any
470 /// fragments that you're joining with), you can use [`with_prefix_str`].
471 ///
472 /// [`with_prefix_str`]: Self::with_prefix_str
473 ///
474 /// # Errors
475 ///
476 /// Returns `Err` if the fragment formed from the combination of `prefix`
477 /// and `self` is invalid. If invalid, an [`Error`] is returned with the
478 /// [`error_kind`] set to `InvalidPrefix`.
479 ///
480 /// The value [`byte_offset`] will *NOT* be set from this function. None of
481 /// the individual characters are invalid, it's just that the combination of
482 /// joining the fragments themselves is invalid.
483 ///
484 /// [`Error`]: crate::Error
485 /// [`error_kind`]: crate::Error::error_kind
486 /// [`byte_offset`]: crate::Error::byte_offset
487 ///
488 /// # Examples
489 ///
490 /// Basic Usage:
491 ///
492 /// ```
493 /// # use typed_ident::presets::unicode::lower_snake::*;
494 /// let fragment = LowerSnakeFragment::new("snake")?;
495 /// let fragment = fragment.with_prefix(
496 /// LowerSnakeFragment::new("lower_")?,
497 /// )?;
498 /// assert_eq!(fragment, "lower_snake");
499 /// # Ok::<(), typed_ident::Error>(())
500 /// ```
501 #[must_use = "this function returns an allocated fragment, it does not mutate the original"]
502 #[inline]
503 pub fn with_prefix(&self, prefix: &Fragment<B, D, P>) -> Result<FragmentBuf<B, D, P>, Error> {
504 let mut buffer = FragmentBuf::with_overhead(prefix, self.len());
505 buffer.push_fragment(self)?;
506 Ok(buffer)
507 }
508
509 /// Returns a heap-allocated fragment with the provided prefix string
510 /// attached to the original fragment. The provided string is first
511 /// converted to a fragment before attempting to append it.
512 ///
513 /// # Errors
514 ///
515 /// Returns `Err` if the fragment formed from the combination of `prefix`
516 /// and `self` is invalid. If invalid, an [`Error`] is returned with the
517 /// [`error_kind`] set to `InvalidPrefix`.
518 ///
519 /// The value [`byte_offset`] *MAY* be set on this function. If the prefix
520 /// string contained invalid characters, this will be set to the byte index
521 /// (from the start of the prefix string) that was invalid.
522 ///
523 /// However, if all characters are independently valid, but one side failed
524 /// to join (because the join itself would make the following character
525 /// invalid), then `byte_offset` will be set to `None`.
526 ///
527 /// [`Error`]: crate::Error
528 /// [`error_kind`]: crate::Error::error_kind
529 /// [`byte_offset`]: crate::Error::byte_offset
530 ///
531 /// # Examples
532 ///
533 /// Basic Usage:
534 ///
535 /// ```
536 /// # use typed_ident::presets::unicode::lower_snake::*;
537 /// let fragment = LowerSnakeFragment::new("snake")?;
538 /// let fragment = fragment.with_prefix_str("lower_")?;
539 /// assert_eq!(fragment, "lower_snake");
540 /// # Ok::<(), typed_ident::Error>(())
541 /// ```
542 #[must_use = "this function returns an allocated fragment, it does not mutate the original"]
543 #[inline]
544 pub fn with_prefix_str(&self, prefix: &str) -> Result<FragmentBuf<B, D, P>, Error> {
545 self.with_prefix(Fragment::new(prefix)?)
546 }
547
548 /// Returns a heap-allocated fragment with the provided suffix attached to
549 /// the original fragment.
550 ///
551 /// It can be a bit cumbersome to use this function in most cases. Instead,
552 /// if you find it easier to work with string data (or you don't have any
553 /// fragments that you're joining with), you can use [`with_suffix_str`].
554 ///
555 /// [`with_suffix_str`]: Self::with_suffix_str
556 ///
557 /// # Errors
558 ///
559 /// Returns `Err` if the fragment formed from the combination of `self` and
560 /// `suffix` is invalid. If invalid, an [`Error`] is returned with the
561 /// [`error_kind`] set to `InvalidPrefix`.
562 ///
563 /// The value [`byte_offset`] will *NOT* be set from this function. None of
564 /// the individual characters are invalid, it's just that the combination of
565 /// joining the fragments themselves is invalid.
566 ///
567 /// [`Error`]: crate::Error
568 /// [`error_kind`]: crate::Error::error_kind
569 /// [`byte_offset`]: crate::Error::byte_offset
570 ///
571 /// # Examples
572 ///
573 /// Basic Usage:
574 ///
575 /// ```
576 /// # use typed_ident::presets::unicode::lower_snake::*;
577 /// let fragment = LowerSnakeFragment::new("snake")?;
578 /// let fragment = fragment.with_suffix(
579 /// LowerSnakeFragment::new("_fragment")?,
580 /// )?;
581 /// assert_eq!(fragment, "snake_fragment");
582 /// # Ok::<(), typed_ident::Error>(())
583 /// ```
584 #[must_use = "this function returns an allocated fragment, it does not mutate the original"]
585 #[inline]
586 pub fn with_suffix(&self, suffix: &Fragment<B, D, P>) -> Result<FragmentBuf<B, D, P>, Error> {
587 let mut buffer = FragmentBuf::with_overhead(self, suffix.len());
588 buffer.push_fragment(suffix)?;
589 Ok(buffer)
590 }
591
592 /// Returns a heap-allocated fragment with the provided suffix string
593 /// attached to the original fragment. The provided string is first
594 /// converted to a fragment before attempting to append it.
595 ///
596 /// # Errors
597 ///
598 /// Returns `Err` if the fragment formed from the combination of `self` and
599 /// `suffix` is invalid. If invalid, an [`Error`] is returned with the
600 /// [`error_kind`] set to `InvalidPrefix`.
601 ///
602 /// The value [`byte_offset`] *MAY* be set on this function. If the suffix
603 /// string contained invalid characters, this will be set to the byte index
604 /// (from the start of the suffix string) that was invalid.
605 ///
606 /// However, if all characters are independently valid, but one side failed
607 /// to join (because the join itself would make the following character
608 /// invalid), then `byte_offset` will be set to `None`.
609 ///
610 /// [`Error`]: crate::Error
611 /// [`error_kind`]: crate::Error::error_kind
612 /// [`byte_offset`]: crate::Error::byte_offset
613 ///
614 /// # Examples
615 ///
616 /// Basic Usage:
617 ///
618 /// ```
619 /// # use typed_ident::presets::unicode::lower_snake::*;
620 /// let fragment = LowerSnakeFragment::new("snake")?;
621 /// let fragment = fragment.with_suffix_str("_fragment")?;
622 /// assert_eq!(fragment, "snake_fragment");
623 /// # Ok::<(), typed_ident::Error>(())
624 /// ```
625 #[must_use = "this function returns an allocated fragment, it does not mutate the original"]
626 #[inline]
627 pub fn with_suffix_str(&self, suffix: &str) -> Result<FragmentBuf<B, D, P>, Error> {
628 self.with_suffix(Fragment::new(suffix)?)
629 }
630}
631
632// -----------------------------------------------------------------------------
633impl<B, D, P> Fragment<B, D, P> {
634 /// Converts a boxed fragment into a boxed string slice.
635 ///
636 /// # Examples
637 ///
638 /// Basic Usage:
639 ///
640 /// ```
641 /// # use typed_ident::*;
642 /// # use typed_ident::presets::unicode::lower_snake::*;
643 /// let fragment: Box<LowerSnakeFragment> =
644 /// Fragment::new_boxed(String::from("snake_fragment"))?;
645 /// let fragment: Box<str> = fragment.into_boxed_str();
646 /// # Ok::<(), typed_ident::Error>(())
647 /// ```
648 #[must_use]
649 #[inline]
650 pub fn into_boxed_str(self: Box<Fragment<B, D, P>>) -> Box<str> {
651 // SAFETY: Fragment is transparent over str, so Box<Fragment> has the
652 // same allocation layout, pointer metadata, alignment, and ownership
653 // behavior as Box<str>.
654 unsafe { Box::from_raw(Box::into_raw(self) as *mut str) }
655 }
656
657 /// Converts a boxed identifier into a fragment buffer.
658 ///
659 /// # Examples
660 ///
661 /// Basic Usage:
662 ///
663 /// ```
664 /// # use typed_ident::*;
665 /// # use typed_ident::presets::unicode::lower_snake::*;
666 /// let fragment: Box<LowerSnakeFragment> =
667 /// Fragment::new_boxed(String::from("snake_fragment"))?;
668 /// let buffer: LowerSnakeFragmentBuf = fragment.into_fragment_buf();
669 /// # Ok::<(), typed_ident::Error>(())
670 /// ```
671 #[must_use]
672 #[inline]
673 pub fn into_fragment_buf(self: Box<Fragment<B, D, P>>) -> FragmentBuf<B, D, P> {
674 FragmentBuf::from_string_unchecked(self.into_string())
675 }
676
677 /// Converts a boxed identifier into a string.
678 ///
679 /// # Examples
680 ///
681 /// Basic Usage:
682 ///
683 /// ```
684 /// # use typed_ident::*;
685 /// # use typed_ident::presets::unicode::lower_snake::*;
686 /// let fragment: Box<LowerSnakeFragment> =
687 /// Fragment::new_boxed(String::from("snake_fragment"))?;
688 /// let buffer: String = fragment.into_string();
689 /// # Ok::<(), typed_ident::Error>(())
690 /// ```
691 #[must_use]
692 #[inline]
693 pub fn into_string(self: Box<Fragment<B, D, P>>) -> String {
694 self.into_boxed_str().into()
695 }
696
697 /// Converts a string into a boxed identifier, bypassing checks.
698 #[must_use]
699 #[inline]
700 pub(crate) fn new_boxed_unchecked(string: String) -> Box<Fragment<B, D, P>> {
701 let boxed_str = string.into_boxed_str();
702 // SAFETY: Fragment is transparent over str, so Box<Fragment> has the
703 // same allocation layout, pointer metadata, alignment, and ownership
704 // behavior as Box<str>.
705 unsafe { Box::from_raw(Box::into_raw(boxed_str) as *mut Fragment<B, D, P>) }
706 }
707
708 /// Converts an identifier into a fragment buffer.
709 ///
710 /// # Examples
711 ///
712 /// Basic Usage:
713 ///
714 /// ```
715 /// # use typed_ident::*;
716 /// # use typed_ident::presets::unicode::lower_snake::*;
717 /// let fragment: &LowerSnakeFragment = Fragment::new("snake_fragment")?;
718 /// let buffer: LowerSnakeFragmentBuf = fragment.to_fragment_buf();
719 /// # Ok::<(), typed_ident::Error>(())
720 /// ```
721 #[must_use]
722 #[inline]
723 pub fn to_fragment_buf(&self) -> FragmentBuf<B, D, P> {
724 FragmentBuf::from_fragment(self)
725 }
726}