Skip to main content

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}