script/dom/file/
filelist.rs

1/* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
4
5use std::slice::Iter;
6
7use dom_struct::dom_struct;
8use servo_base::id::{FileListId, FileListIndex};
9use servo_constellation_traits::SerializableFileList;
10
11use crate::dom::bindings::codegen::Bindings::FileListBinding::FileListMethods;
12use crate::dom::bindings::reflector::{Reflector, reflect_dom_object};
13use crate::dom::bindings::root::{Dom, DomRoot};
14use crate::dom::bindings::serializable::Serializable;
15use crate::dom::bindings::structuredclone::StructuredData;
16use crate::dom::file::File;
17use crate::dom::globalscope::GlobalScope;
18use crate::dom::window::Window;
19use crate::script_runtime::CanGc;
20
21// https://w3c.github.io/FileAPI/#dfn-filelist
22#[dom_struct]
23pub(crate) struct FileList {
24    reflector_: Reflector,
25    list: Vec<Dom<File>>,
26}
27
28impl FileList {
29    #[cfg_attr(crown, expect(crown::unrooted_must_root))]
30    fn new_inherited(files: Vec<Dom<File>>) -> FileList {
31        FileList {
32            reflector_: Reflector::new(),
33            list: files,
34        }
35    }
36
37    pub(crate) fn new(
38        window: &Window,
39        files: Vec<DomRoot<File>>,
40        can_gc: CanGc,
41    ) -> DomRoot<FileList> {
42        reflect_dom_object(
43            Box::new(FileList::new_inherited(
44                files.iter().map(|r| Dom::from_ref(&**r)).collect(),
45            )),
46            window,
47            can_gc,
48        )
49    }
50
51    pub(crate) fn new_in_global(
52        global: &GlobalScope,
53        files: Vec<DomRoot<File>>,
54        can_gc: CanGc,
55    ) -> DomRoot<FileList> {
56        reflect_dom_object(
57            Box::new(FileList::new_inherited(
58                files.iter().map(|r| Dom::from_ref(&**r)).collect(),
59            )),
60            global,
61            can_gc,
62        )
63    }
64
65    pub(crate) fn iter_files(&self) -> Iter<'_, Dom<File>> {
66        self.list.iter()
67    }
68}
69
70impl Serializable for FileList {
71    type Index = FileListIndex;
72    type Data = SerializableFileList;
73
74    /// <https://html.spec.whatwg.org/multipage/#serialization-steps>
75    fn serialize(&self) -> Result<(FileListId, SerializableFileList), ()> {
76        let files = self
77            .list
78            .iter()
79            .map(|file| file.serialized_data())
80            .collect::<Result<Vec<_>, _>>()?;
81        Ok((FileListId::new(), SerializableFileList { files }))
82    }
83
84    /// <https://html.spec.whatwg.org/multipage/#deserialization-steps>
85    fn deserialize(
86        owner: &GlobalScope,
87        serialized: SerializableFileList,
88        can_gc: CanGc,
89    ) -> Result<DomRoot<Self>, ()> {
90        let files = serialized
91            .files
92            .into_iter()
93            .map(|file| File::deserialize(owner, file, can_gc))
94            .collect::<Result<Vec<_>, _>>()?;
95        Ok(FileList::new_in_global(owner, files, can_gc))
96    }
97
98    fn serialized_storage<'a>(
99        reader: StructuredData<'a, '_>,
100    ) -> &'a mut Option<rustc_hash::FxHashMap<FileListId, Self::Data>> {
101        match reader {
102            StructuredData::Reader(r) => &mut r.file_lists,
103            StructuredData::Writer(w) => &mut w.file_lists,
104        }
105    }
106}
107
108impl FileListMethods<crate::DomTypeHolder> for FileList {
109    /// <https://w3c.github.io/FileAPI/#dfn-length>
110    fn Length(&self) -> u32 {
111        self.list.len() as u32
112    }
113
114    /// <https://w3c.github.io/FileAPI/#dfn-item>
115    fn Item(&self, index: u32) -> Option<DomRoot<File>> {
116        if (index as usize) < self.list.len() {
117            Some(DomRoot::from_ref(&*(self.list[index as usize])))
118        } else {
119            None
120        }
121    }
122
123    // check-tidy: no specs after this line
124    fn IndexedGetter(&self, index: u32) -> Option<DomRoot<File>> {
125        self.Item(index)
126    }
127}