Skip to main content

ferroui_android/
platform_icon_loader.rs

1use ferroui_base::media::imaging::{BitmapEncoderOptions, PngBitmapEncoderOptions};
2use ferroui_base::platform::SharedBitmapImpl;
3use ferroui_controls::platform::{IPlatformIconLoader, IWindowIconImpl};
4use std::cell::RefCell;
5use std::fs::File;
6use std::io;
7use std::rc::Rc;
8use std::sync::Arc;
9
10/// An icon loader for a platform that never shows an icon. The platform
11/// registers [`PlatformIconLoaderStub`](crate::PlatformIconLoaderStub), as
12/// the reference does; this class is kept as the reference has it.
13#[derive(Default)]
14pub struct PlatformIconLoader;
15
16impl IPlatformIconLoader for PlatformIconLoader {
17    fn load_icon_from_file(&self, file_name: &str) -> io::Result<Rc<dyn IWindowIconImpl>> {
18        let mut file = File::open(file_name)?;
19        Ok(Rc::new(FakeIcon::new(&mut file)?))
20    }
21
22    fn load_icon_from_stream(&self, stream: &mut dyn io::Read) -> io::Result<Rc<dyn IWindowIconImpl>> {
23        Ok(Rc::new(FakeIcon::new(stream)?))
24    }
25
26    fn load_icon_from_bitmap(&self, bitmap: Arc<SharedBitmapImpl>) -> Rc<dyn IWindowIconImpl> {
27        let mut stream = Vec::new();
28        // A bitmap that cannot be encoded gives an icon without bytes: the contract has no
29        // failure for this member, and the icon is never shown.
30        if bitmap.save(&mut stream, &BitmapEncoderOptions::Png(PngBitmapEncoderOptions::DEFAULT)).is_err() {
31            stream.clear();
32        }
33        // As the reference, which hands over the stream at its end: the icon has no bytes.
34        Rc::new(FakeIcon { stream: RefCell::new(io::Cursor::new(Vec::new())) })
35    }
36}
37
38/// Stores the icon created as a stream to support saving even though an
39/// icon is never shown.
40///
41/// As in the reference, the stream is read from where it stands: the icon
42/// saves its bytes once, because nothing rewinds its stream.
43pub(crate) struct FakeIcon {
44    stream: RefCell<io::Cursor<Vec<u8>>>,
45}
46
47impl FakeIcon {
48    pub(crate) fn new(stream: &mut dyn io::Read) -> io::Result<Self> {
49        let mut bytes = Vec::new();
50        stream.read_to_end(&mut bytes)?;
51        // The copy leaves the stream of the icon at its end.
52        let mut cursor = io::Cursor::new(bytes);
53        cursor.set_position(cursor.get_ref().len() as u64);
54        Ok(Self { stream: RefCell::new(cursor) })
55    }
56}
57
58impl IWindowIconImpl for FakeIcon {
59    fn save(&self, output_stream: &mut dyn io::Write) -> io::Result<()> {
60        io::copy(&mut *self.stream.borrow_mut(), output_stream).map(|_| ())
61    }
62}
63
64#[cfg(test)]
65mod tests {
66    // Not from the reference, which has no tests of the loader.
67    use super::*;
68
69    #[test]
70    fn an_icon_saves_what_is_left_of_its_stream_which_is_nothing() {
71        let icon = PlatformIconLoader.load_icon_from_stream(&mut io::Cursor::new(vec![1, 2, 3])).unwrap();
72        let mut output = Vec::new();
73
74        icon.save(&mut output).unwrap();
75
76        assert!(output.is_empty());
77    }
78}