Skip to main content

pipa/value/
bytes.rs

1// SPDX-FileCopyrightText: Copyright 2026 olav@occy.org
2// SPDX-License-Identifier: MPL-2.0
3
4//! A list of bytes.
5
6use crate::value::Value;
7use crate::value::list::List;
8use crate::value::meta::Meta;
9use crate::value::print::Print;
10use crate::value::tracer::Tracer;
11use bstr::ByteSlice;
12use serde::Deserialize;
13use serde::Serialize;
14use unicode_segmentation::UnicodeSegmentation;
15
16#[derive(Default, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
17pub struct Bytes {
18    #[serde(default, skip_serializing_if = "Tracer::is_empty")]
19    pub(crate) tracer: Tracer,
20    #[serde(default, skip_serializing_if = "Meta::is_empty")]
21    pub(crate) meta: Meta,
22    #[serde(with = "crate::serde::bytes_as_base64")]
23    pub(crate) data: Vec<u8>,
24}
25
26impl core::fmt::Debug for Bytes {
27    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
28        f.debug_struct("Bytes")
29            .field("tracer", &self.tracer)
30            .field("meta", &self.meta)
31            .field("data", &String::from_utf8_lossy(&self.data))
32            .finish()
33    }
34}
35
36impl core::fmt::Display for Bytes {
37    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
38        f.write_str(&String::from_utf8_lossy(&self.clone().print_syntax()))
39    }
40}
41
42impl From<Vec<u8>> for Bytes {
43    fn from(value: Vec<u8>) -> Self {
44        Self {
45            data: value,
46            ..Default::default()
47        }
48    }
49}
50
51impl Bytes {
52    pub(crate) fn trace<T: Into<Tracer>>(&mut self, tracer: T) {
53        self.tracer.trace(tracer);
54    }
55
56    pub(crate) fn tracer(&self) -> &Tracer {
57        &self.tracer
58    }
59
60    pub fn as_bytes(&self) -> &[u8] {
61        &self.data
62    }
63
64    pub fn as_chars(&self) -> List {
65        self.data
66            .chars()
67            .map(String::from)
68            .map(Value::from)
69            .collect()
70    }
71
72    pub fn is_empty(&self) -> bool {
73        self.data.is_empty()
74    }
75
76    pub fn contains(self, needle: &[u8]) -> bool {
77        match (self.is_empty(), needle.is_empty()) {
78            (false, false) => self.data.windows(needle.len()).any(|w| w == needle),
79            (true, false) => false,
80            (_, true) => true,
81        }
82    }
83
84    pub fn join(self) -> Vec<u8> {
85        self.data
86    }
87
88    pub fn clear(mut self) -> Self {
89        self.data = Vec::default();
90        self
91    }
92
93    pub fn trim(mut self) -> Self {
94        let trim = self.data.trim();
95
96        if self.data.len() != trim.len() {
97            self.data = trim.to_vec();
98        }
99
100        self
101    }
102
103    pub fn first(mut self) -> Bytes {
104        self.data = str::from_utf8(&self.data)
105            .unwrap_or_default()
106            .graphemes(true)
107            .next()
108            .map(|v| v.as_bytes().to_vec())
109            .unwrap_or_default();
110        self
111    }
112
113    pub fn last(mut self) -> Bytes {
114        self.data = str::from_utf8(&self.data)
115            .unwrap_or_default()
116            .graphemes(true)
117            .next_back()
118            .map(|v| v.as_bytes().to_vec())
119            .unwrap_or_default();
120        self
121    }
122
123    pub fn rest(mut self) -> Bytes {
124        self.data = str::from_utf8(&self.data)
125            .unwrap_or_default()
126            .graphemes(true)
127            .skip(1)
128            .collect::<String>()
129            .into_bytes();
130        self
131    }
132
133    pub(crate) fn fold(&mut self, mut value: Self) {
134        match value.meta.get(b"internal-insert") {
135            Some(b"prepend") => {
136                value.data.append(&mut self.data);
137                self.data = value.data;
138            }
139            Some(b"append") => {
140                self.data.append(&mut value.data);
141            }
142            _ => {
143                *self = value;
144            }
145        }
146    }
147}