1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
use std::{fmt, rc::Rc};

use itertools::Itertools;

use crate::{
    impl_class, json_format::JsonFormatComponent, memory::MemoryLayout, ObjectPayload, ObjectRef,
    Type,
};

#[derive(Debug, PartialEq, Eq, Clone)]
pub enum FormatStringComponent {
    String(Rc<str>),
    Value(ObjectRef),
}

/// A static format string object
///
/// Very basic right now and supports no runtime functionality.
#[derive(Debug, Eq, PartialEq, Clone)]
pub struct ObjFormatString {
    pub components: Vec<FormatStringComponent>,
}

impl_class! {ObjFormatString, Type::FormatString, {}}

impl ObjFormatString {
    pub fn new(value: Vec<FormatStringComponent>) -> Self {
        ObjFormatString { components: value }
    }
}

impl ObjectPayload for ObjFormatString {
    fn memory_layout(&self) -> &MemoryLayout {
        &MemoryLayout::Unsized
    }

    fn json_fmt(&self, buf: &mut Vec<JsonFormatComponent>) {
        buf.reserve(self.components.len());
        for component in &self.components {
            match component {
                FormatStringComponent::String(text) => {
                    buf.push(JsonFormatComponent::RawText(text.clone()));
                }
                FormatStringComponent::Value(value) => value.payload.json_fmt(buf),
            }
        }
    }
}

impl fmt::Display for ObjFormatString {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.write_fmt(format_args!(
            "`{}`",
            self.components
                .iter()
                .map(|component| match component {
                    FormatStringComponent::String(string) => string.to_string(),
                    FormatStringComponent::Value(obj) => format!("{obj:?}"),
                })
                .format(", ")
        ))
    }
}

impl From<Rc<str>> for ObjFormatString {
    fn from(value: Rc<str>) -> Self {
        ObjFormatString::new(vec![FormatStringComponent::String(value)])
    }
}