Skip to main content

flash_lso/amf0/writer/
array_writer.rs

1use crate::amf0::writer::strict_array_writer::StrictArrayWriter;
2use crate::types::{ECMAArrayObjectValue, Element, ObjectId, Reference, Value};
3
4use super::{CacheKey, ObjWriter, ObjectWriter, TypedObjectWriter};
5
6/// A writer for encoding `ECMAArray` contents
7pub struct ArrayWriter<'a, 'b> {
8    /// The elements in this array
9    pub(crate) elements: Vec<Element>,
10
11    /// The parent of this writer
12    pub(crate) parent: &'a mut dyn ObjWriter<'b>,
13}
14
15impl<'a> ObjWriter<'a> for ArrayWriter<'a, '_> {
16    fn add_element(&mut self, name: &str, s: Value, inc_ref: bool) {
17        if inc_ref {
18            self.make_reference();
19        }
20
21        self.elements.push(Element::new(name.to_string(), s));
22    }
23
24    fn object<'c: 'a, 'd>(
25        &'d mut self,
26        cache_key: CacheKey,
27    ) -> (Option<ObjectWriter<'d, 'c>>, Reference)
28    where
29        'a: 'c,
30        'a: 'd,
31    {
32        if let Some(existing_ref) = self.cache_get(&cache_key) {
33            (None, existing_ref)
34        } else {
35            let r = self.make_reference();
36
37            // Cache this new object
38            self.cache_add(cache_key, r);
39
40            // Return the writer and the reference
41            (
42                Some(ObjectWriter {
43                    elements: Vec::new(),
44                    parent: self,
45                }),
46                r,
47            )
48        }
49    }
50
51    fn array<'c: 'a, 'd>(
52        &'d mut self,
53        cache_key: CacheKey,
54    ) -> (Option<ArrayWriter<'d, 'c>>, Reference)
55    where
56        'a: 'c,
57        'a: 'd,
58    {
59        if let Some(existing_ref) = self.cache_get(&cache_key) {
60            (None, existing_ref)
61        } else {
62            let r = self.make_reference();
63
64            // Cache this new array
65            self.cache_add(cache_key, r);
66
67            // Return the writer and the reference
68            (
69                Some(ArrayWriter {
70                    elements: Vec::new(),
71                    parent: self,
72                }),
73                r,
74            )
75        }
76    }
77
78    fn strict_array<'c: 'a, 'd>(
79        &'d mut self,
80        cache_key: CacheKey,
81    ) -> (Option<StrictArrayWriter<'d, 'c>>, Reference)
82    where
83        'a: 'c,
84        'a: 'd,
85    {
86        if let Some(existing_ref) = self.cache_get(&cache_key) {
87            (None, existing_ref)
88        } else {
89            let r = self.make_reference();
90
91            // Cache this new array
92            self.cache_add(cache_key, r);
93
94            // Return the writer and the reference
95            (
96                Some(StrictArrayWriter {
97                    values: Vec::new(),
98                    parent: self,
99                }),
100                r,
101            )
102        }
103    }
104
105    fn typed_object<'c: 'a, 'd>(
106        &'d mut self,
107        class_name: &str,
108        cache_key: CacheKey,
109    ) -> (Option<TypedObjectWriter<'d, 'c>>, Reference)
110    where
111        'a: 'c,
112        'a: 'd,
113    {
114        if let Some(existing_ref) = self.cache_get(&cache_key) {
115            (None, existing_ref)
116        } else {
117            let r = self.make_reference();
118
119            // Cache this new typed object
120            self.cache_add(cache_key, r);
121
122            // Return the writer and the reference
123            (
124                Some(TypedObjectWriter {
125                    class_name: class_name.to_string(),
126                    elements: Vec::new(),
127                    parent: self,
128                }),
129                r,
130            )
131        }
132    }
133
134    fn make_reference(&mut self) -> Reference {
135        self.parent.make_reference()
136    }
137
138    fn cache_get(&mut self, cache_key: &CacheKey) -> Option<Reference> {
139        self.parent.cache_get(cache_key)
140    }
141
142    fn cache_add(&mut self, cache_key: CacheKey, reference: Reference) {
143        self.parent.cache_add(cache_key, reference);
144    }
145}
146
147impl ArrayWriter<'_, '_> {
148    /// Finalise this array, adding it to it's parent
149    /// If this is not called, the array will not be added
150    pub fn commit<T: AsRef<str>>(self, name: T, length: u32) {
151        self.parent.add_element(
152            name.as_ref(),
153            Value::ECMAArray {
154                id: ObjectId::INVALID,
155                data: ECMAArrayObjectValue {
156                    dense: Vec::new(),
157                    elements: self.elements,
158                    length,
159                },
160            },
161            false,
162        );
163    }
164}