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