Skip to main content

pdf_lib_rs/core/objects/
pdf_array.rs

1use std::fmt;
2use crate::core::syntax::CharCodes;
3use super::pdf_object::{PdfObject, PdfObjectTrait};
4
5/// A PDF array object, e.g., `[ 1 2 3 ]`.
6#[derive(Debug, Clone)]
7pub struct PdfArray {
8    array: Vec<PdfObject>,
9}
10
11impl PdfArray {
12    pub fn new() -> Self {
13        PdfArray { array: Vec::new() }
14    }
15
16    pub fn size(&self) -> usize {
17        self.array.len()
18    }
19
20    pub fn push(&mut self, object: PdfObject) {
21        self.array.push(object);
22    }
23
24    pub fn insert(&mut self, index: usize, object: PdfObject) {
25        self.array.insert(index, object);
26    }
27
28    pub fn remove(&mut self, index: usize) -> PdfObject {
29        self.array.remove(index)
30    }
31
32    pub fn get(&self, index: usize) -> Option<&PdfObject> {
33        self.array.get(index)
34    }
35
36    pub fn set(&mut self, index: usize, object: PdfObject) {
37        self.array[index] = object;
38    }
39
40    pub fn as_slice(&self) -> &[PdfObject] {
41        &self.array
42    }
43}
44
45impl Default for PdfArray {
46    fn default() -> Self {
47        Self::new()
48    }
49}
50
51impl PartialEq for PdfArray {
52    fn eq(&self, _other: &Self) -> bool {
53        // Arrays don't have value equality in the same way
54        false
55    }
56}
57
58impl fmt::Display for PdfArray {
59    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
60        write!(f, "[ ")?;
61        for item in &self.array {
62            write!(f, "{} ", item)?;
63        }
64        write!(f, "]")
65    }
66}
67
68impl PdfObjectTrait for PdfArray {
69    fn size_in_bytes(&self) -> usize {
70        // "[ " + each item + " " + "]"
71        let mut size = 3; // "[ " and "]"
72        for item in &self.array {
73            size += item.size_in_bytes() + 1; // item + space
74        }
75        size
76    }
77
78    fn copy_bytes_into(&self, buffer: &mut [u8], offset: usize) -> usize {
79        let initial_offset = offset;
80        let mut off = offset;
81
82        buffer[off] = CharCodes::LeftSquareBracket;
83        off += 1;
84        buffer[off] = CharCodes::Space;
85        off += 1;
86
87        for item in &self.array {
88            off += item.copy_bytes_into(buffer, off);
89            buffer[off] = CharCodes::Space;
90            off += 1;
91        }
92
93        buffer[off] = CharCodes::RightSquareBracket;
94        off += 1;
95
96        off - initial_offset
97    }
98}
99
100#[cfg(test)]
101mod tests {
102    use super::*;
103    use crate::core::objects::{PdfNumber, PdfName};
104
105    #[test]
106    fn can_push_and_get() {
107        let mut arr = PdfArray::new();
108        arr.push(PdfObject::Number(PdfNumber::of(42.0)));
109        arr.push(PdfObject::Name(PdfName::of("Foo")));
110        assert_eq!(arr.size(), 2);
111    }
112
113    #[test]
114    fn can_be_converted_to_string() {
115        let mut arr = PdfArray::new();
116        arr.push(PdfObject::Number(PdfNumber::of(1.0)));
117        arr.push(PdfObject::Number(PdfNumber::of(2.0)));
118        assert_eq!(arr.to_string(), "[ 1 2 ]");
119    }
120
121    #[test]
122    fn can_insert_and_remove() {
123        let mut arr = PdfArray::new();
124        arr.push(PdfObject::Number(PdfNumber::of(1.0)));
125        arr.push(PdfObject::Number(PdfNumber::of(3.0)));
126        arr.insert(1, PdfObject::Number(PdfNumber::of(2.0)));
127        assert_eq!(arr.size(), 3);
128        assert_eq!(arr.to_string(), "[ 1 2 3 ]");
129
130        arr.remove(1);
131        assert_eq!(arr.to_string(), "[ 1 3 ]");
132    }
133
134    #[test]
135    fn can_provide_size_in_bytes() {
136        let arr = PdfArray::new();
137        assert_eq!(arr.size_in_bytes(), 3); // "[ ]"
138
139        let mut arr2 = PdfArray::new();
140        arr2.push(PdfObject::Number(PdfNumber::of(1.0)));
141        // "[ 1 ]" = 5 bytes
142        assert_eq!(arr2.size_in_bytes(), 5);
143    }
144
145    #[test]
146    fn can_be_serialized() {
147        let mut arr = PdfArray::new();
148        arr.push(PdfObject::Number(PdfNumber::of(1.0)));
149        arr.push(PdfObject::Number(PdfNumber::of(2.0)));
150        let size = arr.size_in_bytes();
151        let mut buffer = vec![0u8; size];
152        arr.copy_bytes_into(&mut buffer, 0);
153        assert_eq!(buffer, b"[ 1 2 ]");
154    }
155}