firefly_rust/graphics/
canvas.rs1use crate::*;
2#[cfg(feature = "alloc")]
3use alloc::boxed::Box;
4#[cfg(feature = "alloc")]
5use alloc::vec;
6
7#[cfg(feature = "alloc")]
29pub struct CanvasBuf {
30 pub(crate) raw: Box<[u8]>,
31}
32
33#[cfg(feature = "alloc")]
34impl CanvasBuf {
35 #[must_use]
37 #[expect(clippy::cast_sign_loss)]
38 pub fn new(s: Size) -> Self {
39 const HEADER_SIZE: usize = 4;
40 let body_size = s.width * s.height / 2;
41 let mut raw = vec![0; HEADER_SIZE + body_size as usize];
42 prepare_slice(&mut raw, s.width);
43 Self {
44 raw: raw.into_boxed_slice(),
45 }
46 }
47
48 #[must_use]
49 pub fn into_image(self) -> ImageBuf {
50 self.into()
51 }
52}
53
54#[cfg(feature = "alloc")]
55impl Canvas for CanvasBuf {
56 unsafe fn as_bytes(&self) -> &[u8] {
57 &self.raw
58 }
59}
60
61pub struct CanvasRef<'a> {
63 pub(crate) raw: &'a [u8],
64}
65
66impl<'a> CanvasRef<'a> {
67 #[must_use]
72 #[expect(clippy::cast_sign_loss)]
73 pub fn new(s: Size, raw: &'a mut [u8]) -> Option<Self> {
74 const HEADER_SIZE: usize = 4;
75 let body_size = s.width * s.height / 2;
76 let exp_size = HEADER_SIZE + body_size as usize;
77 if raw.len() < exp_size {
78 return None;
79 }
80 prepare_slice(raw, s.width);
81 Some(Self {
82 raw: &raw[..exp_size],
83 })
84 }
85
86 #[must_use]
87 pub fn into_image(self) -> ImageRef<'a> {
88 self.into()
89 }
90}
91
92impl Canvas for CanvasRef<'_> {
93 unsafe fn as_bytes(&self) -> &[u8] {
94 self.raw
95 }
96}
97
98pub trait Canvas {
100 unsafe fn as_bytes(&self) -> &[u8];
107}
108
109#[expect(clippy::cast_sign_loss)]
110const fn prepare_slice(raw: &mut [u8], width: i32) {
111 raw[0] = 0x22; raw[1] = width as u8; raw[2] = (width >> 8) as u8; raw[3] = 255; }
116
117impl<T: Canvas> Image for T {
118 unsafe fn as_bytes(&self) -> &[u8] {
119 unsafe { Canvas::as_bytes(self) }
120 }
121}