Skip to main content

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