smt_str/
lib.rs

1//! This crate provides types and utilities for working with SMT-LIB strings.
2//! An SMT-LIB string is a sequence of characters with unicode code points in the range 0x0000 to 0x2FFFF (first two planes of Unicode).
3//! The underlying semantics differ from those of Rust`s native `char` and `String` types:
4//!
5//! - **Character model**: Rust's `char` type represents any Unicode scalar value which is not a surrogate code point.
6//!   In SMT-LIB, a character is a unicode code point in the range 0x0000 to 0x2FFFF, including surrogate code points (which are not valid Rust `char`s).
7//! - **String length**: In Rust, the length of a string is counted in bytes whereas in In SMT-LIB, the length of a string is counted in characters.
8//!   For example, if a character takes more than one byte to encode (such as 🦀), Rust's `String.len()` will return the number of bytes.
9//!   In order to obtain the number of characters, one must count the number of `char`s in the string instead, which can easily lead to errors.
10//! - **Escaping**: In SMT-LIB, the only escape sequences are of the form `\uXXXX` and `\u{X...}`.
11//!   Especially, there are no escape sequences for control characters, such as `\n` or `\t`, that are present in Rust.
12//!
13//! This crate provides a convenient way to work with SMT-LIB strings through the [`SmtChar`] and [`SmtString`] types.
14//! - [`SmtChar`] represents a Unicode code point in the range 0x0000 to 0x2FFFF (including surrogates).
15//! - [`SmtString`] represents a sequence of `SmtChar` values and offers parsing, manipulation, and search utilities that conform to the SMT-LIB specification.
16
17pub mod alphabet;
18#[cfg(feature = "automata")]
19pub mod automata;
20
21#[cfg(feature = "regex")]
22pub mod re;
23#[cfg(feature = "sampling")]
24pub mod sampling;
25
26use std::{
27    fmt::Display,
28    ops::{self, Index},
29};
30
31use num_traits::{SaturatingAdd, SaturatingSub};
32use quickcheck::Arbitrary;
33
34/// The maximum unicode character.
35pub const SMT_MAX_CODEPOINT: u32 = 0x2FFFF;
36
37/// The minimum unicode character.
38pub const SMT_MIN_CODEPOINT: u32 = 0x0000;
39
40/// A Unicode character used in SMT-LIB strings.
41///
42/// In the SMT-LIB string theory, a character is any Unicode code point in the inclusive range
43/// `0x0000` to `0x2FFFF`.
44///
45/// `SmtChar` is a wrapper around a `u32` and provides convenient methods to construct, inspect,
46/// and manipulate SMT-LIB characters safely.
47///
48/// ## Examples
49///
50/// ```
51/// use smt_str::SmtChar;
52///
53/// // Create a new `SmtChar` from a `u32` representing a Unicode code point.
54/// let a = SmtChar::new(0x61); // 'a'
55/// // Get the `u32` representation of the `SmtChar`.
56/// assert_eq!(a.as_u32(), 0x61);
57/// // Get the `char` representation of the `SmtChar`.
58/// assert_eq!(a.as_char(), Some('a'));
59///
60/// // It is also possible to create an `SmtChar` from a `char`.
61/// let b = SmtChar::from('b');
62/// assert_eq!(b.as_u32(), 0x62);
63/// assert_eq!(b.as_char(), Some('b'));
64///
65/// let surrogate = SmtChar::new(0xD800); // valid in SMT-LIB, invalid as Rust `char`
66/// assert_eq!(surrogate.as_char(), None);
67///
68/// // Non-printable characters are escaped when displayed.
69/// let newline = SmtChar::new(0x0A); // '\n'
70/// assert_eq!(newline.to_string(), r#"\u{A}"#);
71/// ```
72#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
73pub struct SmtChar(u32);
74
75impl SmtChar {
76    /// The maximum `SmtChar`.
77    /// This is the unicode code point 0x2FFFF.
78    pub const MAX: Self = Self(SMT_MAX_CODEPOINT);
79
80    /// The minimum `SmtChar`.
81    /// This is the unicode code point 0x0000.
82    pub const MIN: Self = Self(SMT_MIN_CODEPOINT);
83
84    /// Creates a new `SmtChar` from a `u32` code point.
85    /// Panics if `c as u32 > 0x2FFFF`.
86    pub fn new(c: u32) -> Self {
87        assert!(c <= 0x2FFFF, "character out of range: {}", c);
88        SmtChar(c)
89    }
90
91    /// Creates the `SmtChar` with the code point `1`.
92    fn one() -> Self {
93        SmtChar::new(1)
94    }
95
96    /// Get the `char` representation of this `SmtChar`, if it can be represented as a `char`.
97    /// Returns `None` if this `SmtChar` is a surrogate code point.
98    ///
99    ///
100    /// # Examples
101    /// ```
102    /// use smt_str::SmtChar;
103    /// let c = SmtChar::from('a');
104    /// assert_eq!(c.as_char(), Some('a'));
105    /// // This is a surrogate code point and cannot be represented as a `char`.
106    /// assert_eq!(SmtChar::new(55296).as_char(), None);
107    ///```
108    pub fn as_char(self) -> Option<char> {
109        char::from_u32(self.0)
110    }
111
112    /// Get the `u32` representation of this `SmtChar`.
113    /// The `u32` is the unicode code point of this `SmtChar`.
114    ///
115    /// # Examples
116    /// ```
117    /// use smt_str::SmtChar;
118    /// assert_eq!(SmtChar::from('a').as_u32(), 97);
119    /// assert_eq!(SmtChar::from('🦀').as_u32(), 129408);
120    /// ```
121    pub fn as_u32(self) -> u32 {
122        self.0
123    }
124
125    /// Returns the next `SmtChar` in the range 0x0000 to 0x2FFFF.
126    /// Panics if this `SmtChar` is the maximum `SmtChar`.
127    ///
128    /// # Examples
129    /// ```
130    /// use smt_str::SmtChar;
131    /// let c = SmtChar::from('a');
132    /// assert_eq!(c.next(), SmtChar::from('b'));
133    /// ```
134    ///
135    /// Cannot get the next character after the maximum `SmtChar`:
136    /// ```should_panic
137    /// use smt_str::SmtChar;
138    /// let c = SmtChar::MAX;
139    /// let _ = c.next(); // panics
140    /// ```
141    pub fn next(self) -> Self {
142        self + Self::one()
143    }
144
145    /// Returns the next `SmtChar` in the range 0x0000 to 0x2FFFF, if it exists.
146    /// Returns `None` if this `SmtChar` is the maximum `SmtChar`.
147    ///
148    /// # Examples
149    /// ```
150    /// use smt_str::SmtChar;
151    /// let c = SmtChar::from('a');
152    /// assert_eq!(c.try_next(), Some(SmtChar::from('b')));
153    /// assert_eq!(SmtChar::MAX.try_next(), None);
154    /// ```
155    pub fn try_next(self) -> Option<Self> {
156        if self == Self::MAX {
157            None
158        } else {
159            Some(self.next())
160        }
161    }
162
163    /// Like `next`, but instead of panicking when this `SmtChar` is the maximum `SmtChar`, it returns the maximum `SmtChar`.
164    ///
165    /// # Examples
166    /// ```
167    /// use smt_str::SmtChar;
168    /// let c = SmtChar::from('a');
169    /// assert_eq!(c.saturating_next(), SmtChar::from('b'));
170    /// assert_eq!(SmtChar::MAX.saturating_next(), SmtChar::MAX);
171    /// ```
172    pub fn saturating_next(self) -> Self {
173        self.try_next().unwrap_or(Self::MAX)
174    }
175
176    /// Returns the previous `SmtChar` in the range 0x0000 to 0x2FFFF.
177    /// Panics if this `SmtChar` is the minimum `SmtChar`.
178    ///
179    /// # Examples
180    /// ```
181    /// use smt_str::SmtChar;
182    /// let c = SmtChar::from('b');
183    /// assert_eq!(c.prev(), SmtChar::from('a'));
184    /// ```
185    ///
186    /// Cannot get the previous character before the minimum `SmtChar`:
187    ///
188    /// ```should_panic
189    /// use smt_str::SmtChar;
190    /// let c = SmtChar::MIN;
191    /// let _ = c.prev(); // panics
192    /// ```
193    pub fn prev(self) -> Self {
194        self - Self::one()
195    }
196
197    /// Returns the previous `SmtChar` in the range 0x0000 to 0x2FFFF, if it exists.
198    /// Returns `None` if this `SmtChar` is the minimum `SmtChar`.
199    ///
200    /// # Examples
201    /// ```
202    /// use smt_str::SmtChar;
203    /// let c = SmtChar::from('b');
204    /// assert_eq!(c.try_prev(), Some(SmtChar::from('a')));
205    /// assert_eq!(SmtChar::MIN.try_prev(), None);
206    /// ```
207    pub fn try_prev(self) -> Option<Self> {
208        if self == Self::MIN {
209            None
210        } else {
211            Some(self.prev())
212        }
213    }
214
215    /// Like `prev`, but instead of panicking when this `SmtChar` is the minimum `SmtChar`, it returns the minimum `SmtChar`.
216    ///
217    /// # Examples
218    /// ```
219    /// use smt_str::SmtChar;
220    /// let c = SmtChar::from('b');
221    /// assert_eq!(c.saturating_prev(), SmtChar::from('a'));
222    /// assert_eq!(SmtChar::MIN.saturating_prev(), SmtChar::MIN);
223    /// ```
224    pub fn saturating_prev(self) -> Self {
225        self.try_prev().unwrap_or(Self::MIN)
226    }
227
228    /// Returns `true` if this `SmtChar` is a printable ASCII character.
229    /// Printable ASCII characters are in the range 0x00020 to 0x0007E.
230    ///
231    /// # Examples
232    /// ```
233    /// use smt_str::SmtChar;
234    /// assert!(SmtChar::from('a').printable());
235    /// assert!(!SmtChar::from('\n').printable());
236    /// ```
237    pub fn printable(self) -> bool {
238        0x00020 <= self.0 && self.0 < 0x0007E
239    }
240
241    /// Escape this `SmtChar` as a  Unicode escape sequence.
242    /// The escape sequence is of the form `\u{X}` where `X` is the hexadecimal representation of the unicode code point.
243    /// The function always chooses the shortest escape sequence, i.e., it uses the smallest number of digits and does not pad with zeros.
244    ///
245    /// # Examples
246    /// ```
247    /// use smt_str::SmtChar;
248    /// assert_eq!(SmtChar::from('a').escape(), r#"\u{61}"#);
249    /// assert_eq!(SmtChar::from('\n').escape(), r#"\u{A}"#);
250    /// assert_eq!(SmtChar::from('🦀').escape(), r#"\u{1F980}"#);
251    /// assert_eq!(SmtChar::MAX.escape(), r#"\u{2FFFF}"#);
252    /// assert_eq!(SmtChar::MIN.escape(), r#"\u{0}"#);
253    ///
254    /// ```
255    pub fn escape(self) -> String {
256        let mut escaped = String::with_capacity(6);
257        escaped.push('\\');
258        escaped.push('u');
259        escaped.push('{');
260        escaped.push_str(&format!("{:X}", self.0));
261        escaped.push('}');
262        escaped
263    }
264
265    /// Unescape a string that contains escaped characters.
266    /// Escaped characters are of the following form:
267    ///
268    /// - `\uDDDD`
269    /// - `\u{D}`,
270    /// - `\u{DD}`,
271    /// - `\u{DDD}`,
272    /// - `\u{DDDD}`,
273    /// - `\u{DDDDD}`
274    ///
275    /// where `D` is a hexadecimal digit. In the case `\u{DDDDD}`, the first digit must be in the range 0 to 2.
276    /// The function returns `None` if the input string is not a valid escaped character.
277    ///
278    /// # Examples
279    /// ```
280    /// use smt_str::SmtChar;
281    /// assert_eq!(SmtChar::unescape(r#"\u{61}"#), Some(SmtChar::from('a')));
282    /// assert_eq!(SmtChar::unescape(r#"\u{A}"#), Some(SmtChar::from('\n')));
283    /// assert_eq!(SmtChar::unescape(r#"\u{1F980}"#), Some(SmtChar::from('🦀')));
284    /// assert_eq!(SmtChar::unescape(r#"\u{2FFFF}"#), Some(SmtChar::MAX));
285    /// assert_eq!(SmtChar::unescape(r#"\u{0}"#), Some(SmtChar::MIN));
286    ///
287    /// // Invalid escape sequences
288    ///
289    /// assert_eq!(SmtChar::unescape(r#"\u{3000A}"#), None); // out of range
290    /// assert_eq!(SmtChar::unescape(r#"\u{61"#), None); // missing closing brace
291    /// assert_eq!(SmtChar::unescape(r#"\u{}"#), None); // empty digits
292    /// ```
293    pub fn unescape(escaped: &str) -> Option<Self> {
294        let mut chars = escaped.chars();
295        if chars.next()? != '\\' {
296            return None;
297        }
298        if chars.next()? != 'u' {
299            return None;
300        }
301        let mut digits = Vec::with_capacity(5);
302        let mut lparen = false;
303        let mut rparen = false;
304        for c in chars {
305            match c {
306                '{' if !lparen => {
307                    lparen = true;
308                }
309                '}' if lparen => {
310                    rparen = true;
311                }
312                c if !rparen && c.is_ascii_hexdigit() => {
313                    digits.push(c);
314                }
315                _ => {
316                    return None;
317                }
318            }
319        }
320        if lparen && !rparen {
321            return None;
322        }
323        if digits.is_empty() {
324            return None;
325        }
326        // Convert the digits to a u32
327        let mut code = 0;
328        for c in digits {
329            let digit = c.to_digit(16)?;
330            code = code * 16 + digit;
331        }
332        if code > SMT_MAX_CODEPOINT {
333            return None;
334        }
335        Some(SmtChar(code))
336    }
337}
338
339/* Conversion from primitives */
340
341impl From<u8> for SmtChar {
342    fn from(c: u8) -> Self {
343        SmtChar::new(c as u32)
344    }
345}
346
347impl From<u16> for SmtChar {
348    fn from(c: u16) -> Self {
349        SmtChar::new(c as u32)
350    }
351}
352
353impl From<u32> for SmtChar {
354    fn from(c: u32) -> Self {
355        SmtChar::new(c)
356    }
357}
358
359impl From<i32> for SmtChar {
360    fn from(c: i32) -> Self {
361        if c < 0 {
362            panic!("negative character: {}", c);
363        }
364        SmtChar::new(c as u32)
365    }
366}
367
368impl From<char> for SmtChar {
369    fn from(c: char) -> Self {
370        SmtChar::new(c as u32)
371    }
372}
373
374/* Operations */
375
376impl ops::Add<SmtChar> for SmtChar {
377    type Output = SmtChar;
378    /// Adds another `SmtChar` to this `SmtChar`, shifting the unicode code point.
379    /// The sum is the sum of the unicode code points of the two `SmtChar`s.
380    /// Panics if the resulting code point is greater than [SMT_MAX_CODEPOINT] (= `0x2FFFF`).
381    ///
382    /// # Examples
383    /// ```
384    /// use smt_str::SmtChar;
385    /// let c = SmtChar::from('a');
386    /// assert_eq!(c + SmtChar::new(1), SmtChar::from('b'));
387    /// assert_eq!(c + SmtChar::new(25), SmtChar::from('z'));
388    /// ```
389    ///
390    /// Overflowing the maximum code point panics:
391    ///
392    /// ```should_panic
393    /// use smt_str::SmtChar;
394    /// let c = SmtChar::MAX;
395    /// let _ = c + SmtChar::new(1); // panics
396    /// ```
397    fn add(self, rhs: SmtChar) -> Self::Output {
398        SmtChar::new(self.0 + rhs.0)
399    }
400}
401
402impl SaturatingAdd for SmtChar {
403    /// Adds another `SmtChar` to this `SmtChar`, saturating at the maximum unicode code point.
404    ///
405    /// # Examples
406    /// ```
407    /// use smt_str::SmtChar;
408    /// use num_traits::ops::saturating::SaturatingAdd;
409    /// let c = SmtChar::from('a');
410    /// assert_eq!(c.saturating_add(&SmtChar::new(1)), SmtChar::from('b'));
411    /// assert_eq!(c.saturating_add(&SmtChar::new(25)), SmtChar::from('z'));
412    /// let c = SmtChar::MAX;
413    /// assert_eq!(c.saturating_add(&SmtChar::new(1)), SmtChar::MAX);
414    /// ```
415    fn saturating_add(&self, v: &Self) -> Self {
416        let sum = (self.0 + v.0).min(SMT_MAX_CODEPOINT);
417        SmtChar::new(sum)
418    }
419}
420
421impl ops::Sub<SmtChar> for SmtChar {
422    type Output = SmtChar;
423    /// Subtracts another `SmtChar` from this `SmtChar`, shifting the unicode code point.
424    /// The difference is the difference of the unicode code points of the two `SmtChar`s.
425    /// Panics if the resulting code point is less than [SMT_MIN_CODEPOINT] (= `0`).
426    ///
427    /// # Examples
428    /// ```
429    /// use smt_str::SmtChar;
430    /// let c = SmtChar::from('z');
431    /// assert_eq!(c - SmtChar::new(1), SmtChar::from('y'));
432    /// assert_eq!(c - SmtChar::new(25), SmtChar::from('a'));
433    /// ```
434    ///
435    /// Underflowing the minimum code point panics:
436    ///
437    /// ```should_panic
438    /// use smt_str::SmtChar;
439    /// let c = SmtChar::MIN;
440    /// let _ = c - SmtChar::new(1); // panics
441    /// ```
442    fn sub(self, rhs: SmtChar) -> Self::Output {
443        SmtChar::new(self.0 - rhs.0)
444    }
445}
446
447impl SaturatingSub for SmtChar {
448    /// Subtracts another `SmtChar` from this `SmtChar`, saturating at the minimum unicode code point.
449    ///
450    /// # Examples
451    /// ```
452    /// use smt_str::SmtChar;
453    /// let c = SmtChar::from('z');
454    /// use num_traits::ops::saturating::SaturatingSub;
455    /// assert_eq!(c.saturating_sub(&SmtChar::new(1)), SmtChar::from('y'));
456    /// assert_eq!(c.saturating_sub(&SmtChar::new(25)), SmtChar::from('a'));
457    /// let c = SmtChar::MIN;
458    /// assert_eq!(c.saturating_sub(&SmtChar::new(1)), SmtChar::MIN);
459    /// ```
460    fn saturating_sub(&self, v: &Self) -> Self {
461        let diff = self.0.saturating_sub(v.0);
462        SmtChar::new(diff)
463    }
464}
465
466impl Display for SmtChar {
467    /// Display the `SmtChar` as a Unicode character if it is printable.
468    /// Otherwise, display the character as a Unicode escape sequence (see [SmtChar::escape]).
469    /// Additionally, backslashes and quotes are escaped.
470    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
471        if self.printable() {
472            // printable ASCII character are always safe to unwrap
473            let c = self.as_char().unwrap();
474            // Although the character is printable, we still escape it if it is a backslash or a quote
475            if c == '\\' || c == '"' {
476                write!(f, "{}", self.escape())
477            } else {
478                write!(f, "{}", c)
479            }
480        } else {
481            write!(f, "{}", self.escape())
482        }
483    }
484}
485
486/// An iterator over the characters in the range `start` to `end`.
487#[derive(Debug, Clone)]
488pub struct CharIterator {
489    current: SmtChar,
490    end: SmtChar,
491}
492
493impl CharIterator {
494    /// Create a new iterator over the characters in the range `start` to `end` (both inclusively).
495    pub fn new(start: SmtChar, end: SmtChar) -> Self {
496        CharIterator {
497            current: start,
498            end,
499        }
500    }
501}
502impl Iterator for CharIterator {
503    type Item = SmtChar;
504
505    fn next(&mut self) -> Option<Self::Item> {
506        if self.current <= self.end {
507            let c = self.current;
508            self.current = self.current.try_next()?;
509            Some(c)
510        } else {
511            None
512        }
513    }
514}
515
516/// An SMT-LIB string is a sequence of characters with unicode code points in the range 0x0000 to 0x2FFFF (first two planes of Unicode).
517/// The characters are represented by the [`SmtChar`] type.
518///
519/// # Examples
520/// ```
521/// use smt_str::{SmtString, SmtChar};
522///
523/// // Create a new SmtString from a string literal
524/// let s: SmtString = "foo".into();
525///
526/// // Obtain the length of the string
527/// assert_eq!(s.len(), 3);
528///
529/// // SmtStrings have the correct length even for multi-byte characters
530/// let s: SmtString = "🦀".into();
531/// assert_eq!(s.len(), 1);
532///
533/// // In Rust, the length of a string is counted in bytes, not characters
534/// assert_eq!("🦀".len(), 4);
535/// assert_eq!("🦀".chars().count(), 1);
536///
537/// // SmtString can be parsed from a string with escape sequences
538/// let s: SmtString = SmtString::parse(r#"foo\u{61}bar"#);
539/// assert_eq!(s, SmtString::from("fooabar"));
540///
541/// // Printing the string escapes non-printable characters
542/// let s: SmtString = SmtString::from("foo\nbar");
543/// assert_eq!(s.to_string(), r#"foo\u{A}bar"#);
544///
545/// ```
546#[derive(Debug, Clone, PartialEq, Eq, Hash)]
547pub struct SmtString(Vec<SmtChar>);
548
549impl SmtString {
550    /// The empty string.
551    pub fn empty() -> Self {
552        SmtString(Vec::new())
553    }
554
555    /// Create a new SmtString from a vector of SmtChar.
556    pub fn new(chars: Vec<SmtChar>) -> Self {
557        SmtString(chars)
558    }
559
560    /// Parse a string into an SmtString.
561    ///
562    /// The input string can contain escaped characters. The only valid escape sequences are:
563    ///
564    /// - `\uDDDD`
565    /// - `\u{D}`,
566    /// - `\u{DD}`,
567    /// - `\u{DDD}`,
568    /// - `\u{DDDD}`,
569    /// - `\u{DDDDD}`
570    ///
571    /// where `D` is a hexadecimal digit such that the resulting code point is in the range 0x0000 to 0x2FFFF.
572    /// If the string contains valid escape sequences, they are replaced with the corresponding `SmtChar`.
573    /// If the string contains invalid escape sequences, they are treated as literals.
574    /// For example, the string `"foo\u{61}bar"` is parsed as the string `"fooabar"`.
575    /// But the string `"foo\u{61bar"` is parsed as the string `"foo\u{61bar"`.
576    /// The holds for syntactically valid escape sequences that result in code points outside the valid range.
577    /// For example, the string `"foo\u{3000A}bar"` is parsed as the string `"foo\u{3000A}bar"`, since the code point `0x3000A` is outside the valid range.
578    ///
579    /// # Examples
580    /// ```
581    /// use smt_str::{SmtString};
582    /// let s: SmtString = SmtString::parse(r#"foo\u{61}bar"#);
583    /// assert_eq!(s, SmtString::from("fooabar"));
584    ///
585    /// // Invalid escape sequence, treated as literal
586    ///
587    /// let s: SmtString = SmtString::parse(r#"foo\u{61bar"#);
588    /// assert_eq!(s, SmtString::from(r#"foo\u{61bar"#));
589    /// ```
590    pub fn parse(input: &str) -> Self {
591        let mut chars = input.chars().peekable();
592        let mut result = Vec::new();
593        let mut buffer = String::new();
594
595        while let Some(&c) = chars.peek() {
596            if c == '\\' {
597                // Process escaped sequence
598                buffer.clear();
599                while let Some(&c) = chars.peek() {
600                    buffer.push(c);
601                    chars.next(); // Consume character
602                    if c == '}' || (buffer.len() == 6 && !buffer.contains('{')) {
603                        break;
604                    }
605                }
606                if let Some(smt_char) = SmtChar::unescape(&buffer) {
607                    result.push(smt_char);
608                } else {
609                    // Invalid escape sequence, treat as literal
610                    for c in buffer.chars() {
611                        result.push(c.into());
612                    }
613                }
614            } else {
615                // Process regular character
616                result.push(SmtChar(c as u32));
617                chars.next(); // Consume character
618            }
619        }
620
621        SmtString(result)
622    }
623
624    /// Returns whether this string is empty.
625    ///
626    /// # Examples
627    /// ```
628    /// use smt_str::{SmtString};
629    /// assert!(SmtString::empty().is_empty());
630    /// let s: SmtString = "foo".into();
631    /// assert!(!s.is_empty());
632    /// ```
633    pub fn is_empty(&self) -> bool {
634        self.0.is_empty()
635    }
636
637    /// Returns the length of this string.
638    ///
639    /// # Examples
640    /// ```
641    /// use smt_str::{SmtString};
642    /// assert_eq!(SmtString::empty().len(), 0);
643    /// let s: SmtString = "foo".into();
644    /// assert_eq!(s.len(), 3);
645    /// ```
646    ///
647    pub fn len(&self) -> usize {
648        self.0.len()
649    }
650
651    /// Empties this string, removing all characters.
652    /// After calling this method, the string will be empty.
653    ///
654    /// # Examples
655    /// ```
656    /// use smt_str::{SmtString};
657    /// let mut s: SmtString = "foo".into();
658    /// s.clear();
659    /// assert!(s.is_empty());
660    /// ```
661    pub fn clear(&mut self) {
662        self.0.clear();
663    }
664
665    /// Appends the characters of `other` to this string.
666    /// The characters are appended in order.
667    ///
668    /// # Examples
669    /// ```
670    /// use smt_str::{SmtString, SmtChar};
671    /// let mut s: SmtString = "foo".into();
672    /// let other: SmtString = "bar".into();
673    /// s.append(&other);
674    /// let mut iter = s.iter();
675    /// assert_eq!(iter.next(), Some(&SmtChar::from('f')));
676    /// assert_eq!(iter.next(), Some(&SmtChar::from('o')));
677    /// assert_eq!(iter.next(), Some(&SmtChar::from('o')));
678    /// assert_eq!(iter.next(), Some(&SmtChar::from('b')));
679    /// assert_eq!(iter.next(), Some(&SmtChar::from('a')));
680    /// assert_eq!(iter.next(), Some(&SmtChar::from('r')));
681    /// assert_eq!(iter.next(), None);
682    /// ```
683    pub fn append(&mut self, other: &SmtString) {
684        self.0.extend(other.0.iter().copied());
685    }
686
687    /// Pushes a character to the end of this string.
688    ///
689    /// # Examples
690    /// ```
691    /// use smt_str::{SmtString, SmtChar};
692    /// let mut s = SmtString::empty();
693    /// s.push(SmtChar::from('f'));
694    /// s.push(SmtChar::from('o'));
695    /// s.push(SmtChar::from('o'));
696    /// assert_eq!(s, SmtString::from("foo"));  
697    /// ```
698    pub fn push(&mut self, c: impl Into<SmtChar>) {
699        self.0.push(c.into());
700    }
701
702    /// Concatenates this string with `other` and returns the result.
703    /// This is a convenience method that does not modify this string.
704    /// The characters of `other` are appended to the characters of this string, see [append].
705    ///
706    /// # Examples
707    /// ```
708    /// use smt_str::{SmtString};
709    /// let s1 = SmtString::from("foo");
710    /// let s2 = SmtString::from("bar");
711    /// let s3 = s1.concat(&s2);
712    /// assert_eq!(s3, SmtString::from("foobar"));
713    /// ```
714    pub fn concat(&self, other: &SmtString) -> SmtString {
715        let mut s = self.clone();
716        s.append(other);
717        s
718    }
719
720    /// Checks if this string contains a character.
721    ///
722    /// # Examples
723    /// ```
724    /// use smt_str::{SmtString, SmtChar};
725    /// let s: SmtString = "foobar".into();
726    /// assert!(s.contains_char('f'));
727    /// assert!(s.contains_char('o'));
728    /// assert!(s.contains_char('b'));
729    /// assert!(!s.contains_char('z'));
730    /// ```
731    pub fn contains_char(&self, c: impl Into<SmtChar>) -> bool {
732        self.0.contains(&c.into())
733    }
734
735    /// Return whether this string contains another string as a factor.
736    /// This is a naive implementation that checks all possible factors of this string, leading to O(n^2) complexity.
737    ///
738    /// # Examples
739    /// ```
740    /// use smt_str::{SmtString};
741    /// let s: SmtString = "foobar".into();
742    /// assert!(s.contains(&SmtString::empty()));
743    /// assert!(s.contains(&SmtString::from("foo")));
744    /// assert!(s.contains(&SmtString::from("bar")));
745    /// assert!(s.contains(&SmtString::from("oba")));
746    /// assert!(!s.contains(&SmtString::from("baz")));
747    ///
748    /// // The empty string contains only has the empty string as a factor
749    /// let empty: SmtString = SmtString::empty();
750    /// assert!(empty.contains(&SmtString::empty()));
751    /// assert!(!empty.contains(&SmtString::from("foo")));
752    /// ```
753    pub fn contains(&self, factor: &SmtString) -> bool {
754        self.index_of(factor, 0).is_some()
755    }
756
757    /// Find the index of the first occurrence of a factor in the suffix of this string starting at `start`.
758    /// Returns `None` if the factor is not found.
759    /// The empty string is a factor of every string and will always return `Some(0)`.
760    ///
761    /// # Examples
762    /// ```
763    /// use smt_str::{SmtString};
764    /// let s: SmtString = "foobar".into();
765    /// assert_eq!(s.index_of(&SmtString::empty(),0), Some(0));
766    /// assert_eq!(s.index_of(&SmtString::from("foo"),0), Some(0));
767    /// assert_eq!(s.index_of(&SmtString::from("foo"),1), None);
768    /// assert_eq!(s.index_of(&SmtString::from("bar"),0), Some(3));
769    /// assert_eq!(s.index_of(&SmtString::from("oba"),0), Some(2));
770    /// assert_eq!(s.index_of(&SmtString::from("baz"),0), None);
771    ///
772    /// // If the string is empty, the only factor is the empty string
773    /// let empty: SmtString = SmtString::empty();
774    /// assert_eq!(empty.index_of(&SmtString::empty(),0), Some(0));
775    /// assert_eq!(empty.index_of(&SmtString::from("foo"),0), None);
776    /// ```
777    pub fn index_of(&self, factor: &SmtString, start: usize) -> Option<usize> {
778        if self.is_empty() {
779            return if factor.is_empty() { Some(0) } else { None };
780        }
781
782        (start..self.len()).find(|&i| self.drop(i).starts_with(factor))
783    }
784
785    /// Returns whether this string starts with a prefix.
786    /// The empty string is a prefix of every string.
787    ///
788    /// # Examples
789    /// ```
790    /// use smt_str::{SmtString};
791    /// let s: SmtString = "foobar".into();
792    /// assert!(s.starts_with(&SmtString::empty()));
793    /// assert!(s.starts_with(&SmtString::from("foo")));
794    /// assert!(!s.starts_with(&SmtString::from("bar")));
795    /// ```
796    pub fn starts_with(&self, prefix: &SmtString) -> bool {
797        self.0.starts_with(&prefix.0)
798    }
799
800    /// Returns whether this string ends with a suffix.
801    /// The empty string is a suffix of every string.
802    ///
803    /// # Examples
804    /// ```
805    /// use smt_str::{SmtString};
806    /// let s: SmtString = "foobar".into();
807    /// assert!(s.ends_with(&SmtString::empty()));
808    /// assert!(s.ends_with(&SmtString::from("bar")));
809    /// assert!(!s.ends_with(&SmtString::from("foo")));
810    /// ```
811    pub fn ends_with(&self, suffix: &SmtString) -> bool {
812        self.0.ends_with(&suffix.0)
813    }
814
815    /// Returns the first character of this string, if it is not empty.
816    /// Returns `None` if this string is empty.
817    ///
818    /// # Examples
819    /// ```
820    /// use smt_str::{SmtString, SmtChar};
821    /// let s: SmtString = "foo".into();
822    /// assert_eq!(s.first(), Some('f'.into()));
823    /// assert_eq!(SmtString::empty().first(), None);
824    /// ```
825    pub fn first(&self) -> Option<SmtChar> {
826        self.0.first().copied()
827    }
828
829    /// Returns the last character of this string, if it is not empty.
830    /// Returns `None` if this string is empty.
831    ///
832    /// # Examples
833    /// ```
834    /// use smt_str::{SmtString, SmtChar};
835    /// let s: SmtString = "foo".into();
836    /// assert_eq!(s.last(), Some('o'.into()));
837    /// assert_eq!(SmtString::empty().last(), None);
838    /// ```
839    pub fn last(&self) -> Option<SmtChar> {
840        self.0.last().copied()
841    }
842
843    /// Returns the prefix of length `n` of this string.
844    /// If `n` is greater than the length of this string, the entire string is returned.
845    /// If `n` is zero, the empty string is returned.
846    ///
847    /// # Examples
848    /// ```
849    /// use smt_str::{SmtString, SmtChar};
850    /// let s: SmtString = "foo".into();
851    ///
852    /// assert_eq!( s.take(2), SmtString::from("fo"));
853    /// assert!(s.take(10) == s);
854    /// assert!(s.take(0) == SmtString::empty());
855    /// ```
856    ///
857    pub fn take(&self, n: usize) -> SmtString {
858        SmtString(self.0.iter().copied().take(n).collect())
859    }
860
861    /// Returns the suffix of this string after removing the first `n` characters.
862    /// If `n` is greater than the length of this string, the empty string is returned.
863    /// If `n` is zero, the entire string is returned.
864    ///
865    /// # Examples
866    /// ```
867    /// use smt_str::{SmtString, SmtChar};
868    /// let s = SmtString::from("foo");
869    /// assert_eq!(s.drop(2), SmtString::from("o"));
870    /// assert_eq!(s.drop(10), SmtString::empty());
871    /// assert_eq!(s.drop(0), s);
872    /// ```
873    pub fn drop(&self, n: usize) -> SmtString {
874        SmtString(self.0.iter().copied().skip(n).collect())
875    }
876
877    /// Returns the `n`-th character of this string.
878    /// Returns `None` if `n` is greater than or equal to the length of this string.
879    ///
880    /// # Examples
881    /// ```
882    /// use smt_str::{SmtString, SmtChar};
883    /// let s: SmtString = "foo".into();
884    /// assert_eq!(s.nth(0), Some(SmtChar::from('f')));
885    /// assert_eq!(s.nth(1), Some(SmtChar::from('o')));
886    /// assert_eq!(s.nth(2), Some(SmtChar::from('o')));
887    /// assert_eq!(s.nth(3), None);
888    /// ```
889    pub fn nth(&self, n: usize) -> Option<SmtChar> {
890        self.0.get(n).copied()
891    }
892
893    /// Returns the reverse of this string.
894    ///
895    /// # Examples
896    /// ```
897    /// use smt_str::{SmtString, SmtChar};
898    /// let s: SmtString = "foo".into();
899    /// let rev = s.reversed();
900    /// let mut iter = rev.iter();
901    /// assert_eq!(iter.next(), Some(&SmtChar::from('o')));
902    /// assert_eq!(iter.next(), Some(&SmtChar::from('o')));
903    /// assert_eq!(iter.next(), Some(&SmtChar::from('f')));
904    /// assert_eq!(iter.next(), None);
905    /// ```
906    pub fn reversed(&self) -> Self {
907        SmtString(self.0.iter().rev().copied().collect())
908    }
909
910    /// Repeat this string `n` times.
911    /// If `n` is zero, the empty string is returned.
912    /// If this string is empty, the empty string is returned.
913    /// If `n` is one, this string is returned.
914    /// Otherwise, the string is repeated `n` times.
915    ///
916    /// # Examples
917    /// ```
918    /// use smt_str::{SmtString, SmtChar};
919    /// let s = SmtString::from("foo");
920    /// assert_eq!(s.repeat(0), SmtString::empty());
921    /// assert_eq!(s.repeat(1), s);
922    /// assert_eq!(s.repeat(2), SmtString::from("foofoo"));
923    /// ```
924    pub fn repeat(&self, n: usize) -> Self {
925        let mut result = Vec::with_capacity(self.len() * n);
926        for _ in 0..n {
927            result.extend(self.0.iter().copied());
928        }
929        SmtString(result)
930    }
931
932    /// Replaces the first occurrence of `from` in this string with `to`.
933    /// If `from` is not found in this string, the string is returned unchanged.
934    ///
935    /// # Examples
936    /// ```
937    /// use smt_str::{SmtString};
938    /// let s: SmtString = "barbar".into();
939    /// let from: SmtString = "bar".into();
940    /// let to: SmtString = "foo".into();
941    /// assert_eq!(s.replace(&from, &to), SmtString::from("foobar"));
942    /// ```
943    pub fn replace(&self, from: &SmtString, to: &SmtString) -> SmtString {
944        let mut result = SmtString::empty();
945        if let Some(j) = self.index_of(from, 0) {
946            result.append(&self.take(j));
947            result.append(to);
948            let i = j + from.len();
949            result.append(&self.drop(i));
950        } else {
951            result = self.clone();
952        }
953        result
954    }
955
956    /// Replaces all occurrences of `from` in this string with `to`.
957    /// If `from` is not found in this string, the string is returned unchanged.
958    /// If `from` is the empty string, the string is returned unchanged.
959    ///
960    /// # Examples
961    /// ```
962    /// use smt_str::{SmtString};
963    /// let s: SmtString = "barbar".into();
964    /// let from: SmtString = "bar".into();
965    /// let to: SmtString = "foo".into();
966    /// assert_eq!(s.replace_all(&from, &to), SmtString::from("foofoo"));
967    /// ```
968    pub fn replace_all(&self, from: &SmtString, to: &SmtString) -> SmtString {
969        if from.is_empty() || self.is_empty() {
970            return self.clone(); // No changes needed if `from` is empty or `self` is empty
971        }
972
973        let mut result = SmtString::empty();
974        let mut current = self.clone();
975
976        while let Some(j) = current.index_of(from, 0) {
977            result.append(&current.take(j));
978            result.append(to);
979            let i = j + from.len();
980            current = current.drop(i);
981        }
982
983        result.append(&current);
984        result
985    }
986
987    /// Returns an iterator over the characters of this string.
988    pub fn iter(&self) -> std::slice::Iter<SmtChar> {
989        self.0.iter()
990    }
991}
992
993/* Conversions */
994
995impl FromIterator<SmtChar> for SmtString {
996    fn from_iter<I: IntoIterator<Item = SmtChar>>(iter: I) -> Self {
997        SmtString(iter.into_iter().collect())
998    }
999}
1000
1001impl FromIterator<SmtString> for SmtString {
1002    fn from_iter<I: IntoIterator<Item = SmtString>>(iter: I) -> Self {
1003        iter.into_iter()
1004            .fold(SmtString::empty(), |acc, s| acc.concat(&s))
1005    }
1006}
1007
1008impl From<&str> for SmtString {
1009    fn from(s: &str) -> Self {
1010        SmtString(s.chars().map(SmtChar::from).collect())
1011    }
1012}
1013
1014impl From<String> for SmtString {
1015    fn from(s: String) -> Self {
1016        SmtString::from(s.as_str())
1017    }
1018}
1019
1020impl From<SmtChar> for SmtString {
1021    fn from(c: SmtChar) -> Self {
1022        SmtString(vec![c])
1023    }
1024}
1025
1026impl Index<usize> for SmtString {
1027    type Output = SmtChar;
1028
1029    fn index(&self, index: usize) -> &Self::Output {
1030        &self.0[index]
1031    }
1032}
1033
1034impl Display for SmtString {
1035    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1036        for c in &self.0 {
1037            write!(f, "{}", c)?;
1038        }
1039        Ok(())
1040    }
1041}
1042
1043impl Arbitrary for SmtChar {
1044    fn arbitrary(g: &mut quickcheck::Gen) -> Self {
1045        let code = u32::arbitrary(g) % (SMT_MAX_CODEPOINT + 1);
1046        SmtChar(code)
1047    }
1048}
1049
1050impl Arbitrary for SmtString {
1051    fn arbitrary(g: &mut quickcheck::Gen) -> Self {
1052        let len = usize::arbitrary(g) % 100;
1053        let chars = std::iter::repeat_with(|| SmtChar::arbitrary(g))
1054            .take(len)
1055            .collect();
1056        SmtString(chars)
1057    }
1058}
1059
1060#[cfg(test)]
1061mod tests {
1062
1063    use quickcheck::TestResult;
1064    use quickcheck_macros::quickcheck;
1065
1066    use super::*;
1067
1068    #[quickcheck]
1069    fn next_prev_inverse(s: SmtChar) -> TestResult {
1070        if s == SmtChar::MAX {
1071            return TestResult::discard();
1072        }
1073        let next = s.next();
1074        assert_eq!(next.prev(), s);
1075        TestResult::passed()
1076    }
1077
1078    #[quickcheck]
1079    fn prev_next_inverse(s: SmtChar) -> TestResult {
1080        if s == SmtChar::MIN {
1081            return TestResult::discard();
1082        }
1083        let prev = s.prev();
1084        assert_eq!(prev.next(), s);
1085        TestResult::passed()
1086    }
1087
1088    #[test]
1089    #[should_panic]
1090    fn next_past_max() {
1091        SmtChar::MAX.next();
1092    }
1093
1094    #[test]
1095    #[should_panic]
1096    fn prev_past_min() {
1097        SmtChar::MIN.prev();
1098    }
1099
1100    #[test]
1101    fn test_unescape_valid() {
1102        assert_eq!(SmtChar::unescape(r#"\u000A"#), Some(SmtChar(0x000A)));
1103        assert_eq!(SmtChar::unescape(r#"\u{A}"#), Some(SmtChar(0x000A)));
1104        assert_eq!(SmtChar::unescape(r#"\u{0A}"#), Some(SmtChar(0x000A)));
1105        assert_eq!(SmtChar::unescape(r#"\u{00A}"#), Some(SmtChar(0x000A)));
1106        assert_eq!(SmtChar::unescape(r#"\u{000A}"#), Some(SmtChar(0x000A)));
1107        assert_eq!(SmtChar::unescape(r#"\u{000A}"#), Some(SmtChar(0x000A)));
1108        assert_eq!(SmtChar::unescape(r#"\u{0000A}"#), Some(SmtChar(0x000A)));
1109    }
1110
1111    #[test]
1112    fn test_unescape_empty() {
1113        assert_eq!(SmtChar::unescape(r#"\u{}"#), None);
1114    }
1115
1116    #[test]
1117    fn test_unescape_too_large() {
1118        assert_eq!(SmtChar::unescape(r#"\u{3000A}"#), None);
1119        assert_eq!(SmtChar::unescape(r#"\u{4000A}"#), None);
1120        assert_eq!(SmtChar::unescape(r#"\u{5000A}"#), None);
1121        assert_eq!(SmtChar::unescape(r#"\u{F000A}"#), None);
1122    }
1123
1124    #[test]
1125    fn test_unescape_not_hex() {
1126        assert_eq!(SmtChar::unescape(r#"\u{G}"#), None);
1127        assert_eq!(SmtChar::unescape(r#"\u000H"#), None);
1128        assert_eq!(SmtChar::unescape(r#"\u{39v}"#), None);
1129        assert_eq!(SmtChar::unescape(r#"\u{J}"#), None);
1130    }
1131
1132    #[test]
1133    fn test_unescape_invalid_braces() {
1134        assert_eq!(SmtChar::unescape(r#"\u{000A"#), None);
1135        assert_eq!(SmtChar::unescape(r#"\u000A}"#), None);
1136        assert_eq!(SmtChar::unescape(r#"\u{0{00A}"#), None);
1137        assert_eq!(SmtChar::unescape(r#"\u{0}00A}"#), None);
1138    }
1139
1140    #[test]
1141    fn test_unescape_invalid_prefix() {
1142        assert_eq!(SmtChar::unescape(r#"u{000A}"#), None);
1143        assert_eq!(SmtChar::unescape(r#"\{000A}"#), None);
1144        assert_eq!(SmtChar::unescape(r#"\u000A}"#), None);
1145    }
1146
1147    #[quickcheck]
1148    fn test_escape_unescape_inverse(c: u32) -> TestResult {
1149        if c > SMT_MAX_CODEPOINT {
1150            return TestResult::discard();
1151        }
1152        let smt_char = SmtChar::new(c);
1153        assert_eq!(smt_char, SmtChar::unescape(&smt_char.escape()).unwrap());
1154        TestResult::passed()
1155    }
1156
1157    #[quickcheck]
1158    fn append_empty_right_neutral(s: SmtString) {
1159        let mut s1 = s.clone();
1160        s1.append(&SmtString::empty());
1161        assert_eq!(s1, s);
1162    }
1163
1164    #[quickcheck]
1165    fn append_empty_left_neutral(s: SmtString) {
1166        let mut s1 = SmtString::empty();
1167        s1.append(&s);
1168        assert_eq!(s1, s);
1169    }
1170
1171    #[quickcheck]
1172    fn reverse_reverse_inverse(s: SmtString) {
1173        let rev = s.reversed();
1174        assert_eq!(rev.reversed(), s);
1175    }
1176
1177    #[test]
1178    fn test_parse_valid_strings_without_escaped() {
1179        assert_eq!(
1180            SmtString::parse("foo"),
1181            SmtString(vec![
1182                SmtChar('f' as u32),
1183                SmtChar('o' as u32),
1184                SmtChar('o' as u32),
1185            ])
1186        );
1187        assert_eq!(
1188            SmtString::parse("123!@#"),
1189            SmtString(vec![
1190                SmtChar('1' as u32),
1191                SmtChar('2' as u32),
1192                SmtChar('3' as u32),
1193                SmtChar('!' as u32),
1194                SmtChar('@' as u32),
1195                SmtChar('#' as u32)
1196            ])
1197        );
1198    }
1199
1200    #[test]
1201    fn test_parse_valid_string_with_one_escape() {
1202        assert_eq!(
1203            SmtString::parse(r#"a\u0042c"#),
1204            SmtString(vec![
1205                SmtChar('a' as u32),
1206                SmtChar('B' as u32), // Unicode for 'B'
1207                SmtChar('c' as u32)
1208            ])
1209        );
1210
1211        assert_eq!(
1212            SmtString::parse(r#"x\u{41}y"#),
1213            SmtString(vec![
1214                SmtChar('x' as u32),
1215                SmtChar('A' as u32), // Unicode for 'A'
1216                SmtChar('y' as u32)
1217            ])
1218        );
1219
1220        assert_eq!(
1221            SmtString::parse(r#"\u{1F600}"#), // Unicode for 😀
1222            SmtString(vec![SmtChar(0x1F600)])
1223        );
1224    }
1225
1226    #[test]
1227    fn test_parse_valid_string_with_multiple_escape() {
1228        assert_eq!(
1229            SmtString::parse(r#"abc\u0044\u{45}f"#),
1230            SmtString(vec![
1231                SmtChar('a' as u32),
1232                SmtChar('b' as u32),
1233                SmtChar('c' as u32),
1234                SmtChar('D' as u32), // Unicode for 'D'
1235                SmtChar('E' as u32), // Unicode for 'E'
1236                SmtChar('f' as u32),
1237            ])
1238        );
1239
1240        assert_eq!(
1241            SmtString::parse(r#"\u{1F604} smile \u{1F60A}"#), // 😄 smile 😊
1242            SmtString(vec![
1243                SmtChar(0x1F604), // 😄
1244                SmtChar(' ' as u32),
1245                SmtChar('s' as u32),
1246                SmtChar('m' as u32),
1247                SmtChar('i' as u32),
1248                SmtChar('l' as u32),
1249                SmtChar('e' as u32),
1250                SmtChar(' ' as u32),
1251                SmtChar(0x1F60A), // 😊
1252            ])
1253        );
1254    }
1255
1256    #[test]
1257    fn test_parse_invalid_escape_sequences() {
1258        // Missing closing brace
1259        let s = r#"\u{123"#;
1260        let expected = SmtString::new(s.chars().map(SmtChar::from).collect());
1261        assert_eq!(SmtString::parse(s), expected);
1262
1263        // Non-hex character in escape sequence
1264        let s = r#"\u{12G3}"#;
1265        let expected = SmtString::new(s.chars().map(SmtChar::from).collect());
1266        assert_eq!(SmtString::parse(s), expected);
1267
1268        // Escape sequence too long
1269        let s = r#"\u{123456}"#;
1270        let expected = SmtString::new(s.chars().map(SmtChar::from).collect());
1271        assert_eq!(SmtString::parse(s), expected);
1272
1273        // Escape sequence without digits
1274        let s = r#"\u{}"#;
1275        let expected = SmtString::new(s.chars().map(SmtChar::from).collect());
1276        assert_eq!(SmtString::parse(s), expected);
1277
1278        // Invalid escape sequence (SMT 2.5 style)
1279        let s = r#"\x1234"#;
1280        let expected = SmtString::new(s.chars().map(SmtChar::from).collect());
1281        assert_eq!(SmtString::parse(s), expected);
1282
1283        // Unicode above allowed SMT max
1284        let s = r#"\u{110000}"#;
1285        let expected = SmtString::new(s.chars().map(SmtChar::from).collect());
1286        assert_eq!(SmtString::parse(s), expected);
1287    }
1288
1289    #[quickcheck]
1290    fn test_print_parse_inverse(s: SmtString) {
1291        let s1 = s.to_string();
1292        let s2 = SmtString::parse(&s1);
1293        assert_eq!(s, s2);
1294    }
1295
1296    #[quickcheck]
1297    fn index_of_empty_is_always_zero(s: SmtString) {
1298        assert_eq!(s.index_of(&SmtString::empty(), 0), Some(0));
1299    }
1300
1301    #[quickcheck]
1302    fn contains_empty(s: SmtString) {
1303        assert!(s.contains(&SmtString::empty()))
1304    }
1305
1306    #[test]
1307    fn test_replace_at_start() {
1308        let s: SmtString = "foobar".into();
1309        let from: SmtString = "foo".into();
1310        let to: SmtString = "bar".into();
1311        assert_eq!(s.replace(&from, &to), "barbar".into());
1312    }
1313
1314    #[test]
1315    fn test_replace_at_end() {
1316        let s: SmtString = "foobar".into();
1317        let from: SmtString = "bar".into();
1318        let to: SmtString = "foo".into();
1319        assert_eq!(s.replace(&from, &to), "foofoo".into());
1320    }
1321
1322    #[test]
1323    fn test_replace_no_match() {
1324        let s: SmtString = "abcdef".into();
1325        let from: SmtString = "xyz".into();
1326        let to: SmtString = "123".into();
1327        assert_eq!(s.replace(&from, &to), s);
1328    }
1329
1330    #[test]
1331    fn test_replace_empty_from() {
1332        let s: SmtString = "abcdef".into();
1333        let from: SmtString = "".into();
1334        let to: SmtString = "XYZ".into();
1335        assert_eq!(s.replace(&from, &to), "XYZabcdef".into()); // Empty string is inserted at the beginning
1336    }
1337
1338    #[test]
1339    fn test_replace_empty_to() {
1340        let s: SmtString = "abcdef".into();
1341        let from: SmtString = "cd".into();
1342        let to: SmtString = "".into();
1343        assert_eq!(s.replace(&from, &to), "abef".into()); // `cd` is removed
1344    }
1345
1346    #[test]
1347    fn test_replace_full_string() {
1348        let s: SmtString = "abcdef".into();
1349        let from: SmtString = "abcdef".into();
1350        let to: SmtString = "xyz".into();
1351        assert_eq!(s.replace(&from, &to), "xyz".into());
1352    }
1353
1354    #[test]
1355    fn test_replace_repeated_pattern() {
1356        let s: SmtString = "abcabcabc".into();
1357        let from: SmtString = "abc".into();
1358        let to: SmtString = "x".into();
1359        assert_eq!(s.replace(&from, &to), "xabcabc".into()); // Only first occurrence is replaced
1360    }
1361
1362    #[test]
1363    fn test_replace_single_character() {
1364        let s: SmtString = "banana".into();
1365        let from: SmtString = "a".into();
1366        let to: SmtString = "o".into();
1367        assert_eq!(s.replace(&from, &to), "bonana".into()); // Only first 'a' is replaced
1368    }
1369
1370    #[test]
1371    fn test_replace_all_basic() {
1372        let s: SmtString = "foobarbar".into();
1373        let from: SmtString = "bar".into();
1374        let to: SmtString = "foo".into();
1375        assert_eq!(s.replace_all(&from, &to), "foofoofoo".into());
1376    }
1377
1378    #[test]
1379    fn test_replace_all_complete() {
1380        let s: SmtString = "abcabcabc".into();
1381        let from: SmtString = "abc".into();
1382        let to: SmtString = "xyz".into();
1383        assert_eq!(s.replace_all(&from, &to), "xyzxyzxyz".into());
1384    }
1385
1386    #[test]
1387    fn test_replace_all_no_match() {
1388        let s: SmtString = "abcdef".into();
1389        let from: SmtString = "xyz".into();
1390        let to: SmtString = "123".into();
1391        assert_eq!(s.replace_all(&from, &to), "abcdef".into());
1392    }
1393
1394    #[test]
1395    fn test_replace_all_empty_from() {
1396        let s: SmtString = "abcdef".into();
1397        let from: SmtString = "".into();
1398        let to: SmtString = "XYZ".into();
1399        assert_eq!(s.replace_all(&from, &to), s); // No-op
1400    }
1401
1402    #[test]
1403    fn test_replace_all_empty_to() {
1404        let s: SmtString = "banana".into();
1405        let from: SmtString = "a".into();
1406        let to: SmtString = "".into();
1407        assert_eq!(s.replace_all(&from, &to), "bnn".into()); // All 'a's are removed
1408    }
1409
1410    #[test]
1411    fn test_replace_all_full_string() {
1412        let s: SmtString = "abcdef".into();
1413        let from: SmtString = "abcdef".into();
1414        let to: SmtString = "xyz".into();
1415        assert_eq!(s.replace_all(&from, &to), "xyz".into());
1416    }
1417
1418    #[test]
1419    fn test_replace_all_overlapping_occurrences() {
1420        let s: SmtString = "aaaa".into();
1421        let from: SmtString = "aa".into();
1422        let to: SmtString = "b".into();
1423        assert_eq!(s.replace_all(&from, &to), "bb".into()); // "aa" -> "b", then another "aa" -> "b"
1424    }
1425
1426    #[test]
1427    fn test_replace_all_overlapping_occurrences_2() {
1428        let s: SmtString = "aaa".into();
1429        let from: SmtString = "aa".into();
1430        let to: SmtString = "b".into();
1431        assert_eq!(s.replace_all(&from, &to), "ba".into()); // "aa" -> "b", then another "aa" -> "b"
1432    }
1433
1434    #[test]
1435    fn test_replace_all_overlapping_occurrences_3() {
1436        let s: SmtString = "aaa".into();
1437        let from: SmtString = "aa".into();
1438        let to: SmtString = "aaa".into();
1439        assert_eq!(s.replace_all(&from, &to), "aaaa".into());
1440    }
1441}