llvm-native-core 0.1.16

LLVM-native core semantic engine — IR, CodeGen, X86 MC, Clang frontend pipeline
//! LLVM Twine — efficient string concatenation without intermediate allocations.
//!
//! Clean-room behavioral reconstruction.
//! @llvm_behavior: Twine is a lightweight rope for constructing temporary
//!   strings. It builds a binary tree of string pieces (StringRef, integers,
//!   floats, other Twines) and materializes them to a raw_ostream or
//!   SmallVector<char> on demand — avoiding intermediate heap allocations.

use crate::support::string_ref::StringRef;
use std::fmt;

/// A node in the Twine binary tree.
#[derive(Debug, Clone)]
enum TwineKind<'a> {
    /// A leaf: a string reference
    Str(StringRef<'a>),
    /// A leaf: an owned string
    String(std::string::String),
    /// A leaf: a signed integer
    Int(i64),
    /// A leaf: an unsigned integer
    UInt(u64),
    /// A leaf: a char
    Char(char),
    /// A concatenation of two twines
    Concat(Box<Twine<'a>>, Box<Twine<'a>>),
    /// A null twine (empty)
    Null,
}

/// Twine — lazy string concatenation.
///
/// @llvm_behavior: Twine can be constructed from StringRef, &str, i64, u64,
///   unsigned, int, char, and other Twines. Concatenations are built as
///   a binary tree and materialized by to_string() or to_vector().
#[derive(Debug, Clone)]
pub struct Twine<'a> {
    kind: TwineKind<'a>,
}

impl<'a> Twine<'a> {
    /// Create a null (empty) Twine.
    pub fn null() -> Self {
        Self {
            kind: TwineKind::Null,
        }
    }

    /// Returns true if this Twine is null/empty.
    pub fn is_null(&self) -> bool {
        matches!(self.kind, TwineKind::Null)
    }

    /// Materialize the Twine to a String.
    /// Note: Display provides to_string(), but this explicit method provides
    /// LLVM-compatible API parity.
    #[allow(clippy::inherent_to_string_shadow_display)]
    pub fn to_string(&self) -> std::string::String {
        let mut buf = std::string::String::new();
        self.write_to(&mut buf);
        buf
    }

    /// Write the Twine content to a String buffer.
    fn write_to(&self, buf: &mut std::string::String) {
        match &self.kind {
            TwineKind::Null => {}
            TwineKind::Str(s) => buf.push_str(s.data()),
            TwineKind::String(s) => buf.push_str(s),
            TwineKind::Int(i) => buf.push_str(&i.to_string()),
            TwineKind::UInt(u) => buf.push_str(&u.to_string()),
            TwineKind::Char(c) => buf.push(*c),
            TwineKind::Concat(a, b) => {
                a.write_to(buf);
                b.write_to(buf);
            }
        }
    }

    /// Concatenate with another Twine (consuming self).
    pub fn concat(self, other: Twine<'a>) -> Twine<'a> {
        if self.is_null() {
            return other;
        }
        if other.is_null() {
            return self;
        }
        Twine {
            kind: TwineKind::Concat(Box::new(self), Box::new(other)),
        }
    }
}

// === Construction from various types ===

impl<'a> From<StringRef<'a>> for Twine<'a> {
    fn from(s: StringRef<'a>) -> Self {
        Self {
            kind: TwineKind::Str(s),
        }
    }
}

impl<'a> From<&'a str> for Twine<'a> {
    fn from(s: &'a str) -> Self {
        Self {
            kind: TwineKind::Str(StringRef::new(s)),
        }
    }
}

impl From<std::string::String> for Twine<'_> {
    fn from(s: std::string::String) -> Self {
        Self {
            kind: TwineKind::String(s),
        }
    }
}

impl From<i64> for Twine<'_> {
    fn from(i: i64) -> Self {
        Self {
            kind: TwineKind::Int(i),
        }
    }
}

impl From<i32> for Twine<'_> {
    fn from(i: i32) -> Self {
        Twine::from(i as i64)
    }
}

impl From<u64> for Twine<'_> {
    fn from(u: u64) -> Self {
        Self {
            kind: TwineKind::UInt(u),
        }
    }
}

impl From<u32> for Twine<'_> {
    fn from(u: u32) -> Self {
        Twine::from(u as u64)
    }
}

impl From<usize> for Twine<'_> {
    fn from(u: usize) -> Self {
        Twine::from(u as u64)
    }
}

impl From<char> for Twine<'_> {
    fn from(c: char) -> Self {
        Self {
            kind: TwineKind::Char(c),
        }
    }
}

impl fmt::Display for Twine<'_> {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "{}", self.to_string())
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_twine_concat() {
        let t = Twine::from("hello")
            .concat(Twine::from(" "))
            .concat(Twine::from("world"));
        assert_eq!(t.to_string(), "hello world");
    }

    #[test]
    fn test_twine_int() {
        let t = Twine::from("n=").concat(Twine::from(42i64));
        assert_eq!(t.to_string(), "n=42");
    }

    #[test]
    fn test_twine_null() {
        let t = Twine::null();
        assert_eq!(t.to_string(), "");
    }

    #[test]
    fn test_twine_char() {
        let t = Twine::from('A').concat(Twine::from("BC"));
        assert_eq!(t.to_string(), "ABC");
    }
}