refactor(core/rust): improve BinaryData

* add direct reference to a Gc<[u8]> slice, so that we are not forced
  to create a Python bytes object for allocated data
* add From implementations
matejcik 2 weeks ago
parent 79f70fc690
commit 333595ced7

@ -1,4 +1,4 @@
use crate::error::Error;
use crate::{error::Error, micropython::gc::Gc};
#[cfg(feature = "micropython")]
use crate::micropython::{buffer::get_buffer, obj::Obj};
@ -78,23 +78,11 @@ pub enum BinaryData<'a> {
Slice(&'a [u8]),
#[cfg(feature = "micropython")]
Object(Obj),
#[cfg(feature = "micropython")]
AllocatedSlice(Gc<[u8]>),
}
impl<'a> BinaryData<'a> {
/// Creates a new `BinaryData` from a slice of binary data.
pub fn from_slice(data: &'a [u8]) -> Self {
Self::Slice(data)
}
/// Creates a new `BinaryData` from a micropython `bytes` object.
#[cfg(feature = "micropython")]
pub fn from_object(obj: Obj) -> Result<Self, Error> {
if !obj.is_bytes() {
return Err(Error::TypeError);
}
Ok(Self::Object(obj))
}
/// Returns `true` if the binary data is empty.
pub fn is_empty(&self) -> bool {
self.len() == 0
@ -114,17 +102,15 @@ impl<'a> BinaryData<'a> {
// note above.
#[cfg(feature = "micropython")]
Self::Object(obj) => unsafe { unwrap!(get_buffer(*obj)) },
#[cfg(feature = "micropython")]
Self::AllocatedSlice(data) => data,
}
}
/// Returns the length of the binary data in bytes.
pub fn len(&self) -> usize {
match self {
Self::Slice(data) => data.len(),
#[cfg(feature = "micropython")]
// SAFETY: We expect no existing mutable reference.
Self::Object(obj) => unsafe { unwrap!(get_buffer(*obj)).len() },
}
// SAFETY: reference is discarded immediately
unsafe { self.data().len() }
}
/// Reads binary data from the source into the buffer.
@ -150,6 +136,14 @@ impl<'a> BinaryData<'a> {
buff[..size].copy_from_slice(&data[ofs..ofs + size]);
size
}
#[cfg(feature = "micropython")]
Self::AllocatedSlice(data) => {
let remaining = data.len().saturating_sub(ofs);
let size = buff.len().min(remaining);
buff[..size].copy_from_slice(&data[ofs..ofs + size]);
size
}
}
}
}
@ -165,3 +159,26 @@ impl<'a> PartialEq for BinaryData<'a> {
}
}
}
impl From<Gc<[u8]>> for BinaryData<'static> {
fn from(data: Gc<[u8]>) -> Self {
Self::AllocatedSlice(data)
}
}
impl TryFrom<Obj> for BinaryData<'static> {
type Error = Error;
fn try_from(obj: Obj) -> Result<Self, Self::Error> {
if !obj.is_bytes() {
return Err(Error::TypeError);
}
Ok(Self::Object(obj))
}
}
impl<'a> From<&'a [u8]> for BinaryData<'a> {
fn from(data: &'a [u8]) -> Self {
Self::Slice(data)
}
}

@ -181,8 +181,5 @@ pub fn get_user_custom_image() -> Result<BinaryData<'static>, Error> {
let mut data = Gc::<[u8]>::new_slice(len)?;
// SAFETY: buffer is freshly allocated so nobody else has it.
load_avatar(unsafe { Gc::<[u8]>::as_mut(&mut data) })?;
// Convert to mp_obj_bytes
let bytes = Obj::try_from(data.as_ref())?;
// Convert to BinaryData
BinaryData::from_object(bytes)
Ok(data.into())
}

@ -4,7 +4,6 @@ use heapless::Vec;
use crate::{
error::Error,
io::BinaryData,
maybe_trace::MaybeTrace,
micropython::{
buffer::StrBuffer, gc::Gc, iter::IterBuf, list::List, map::Map, module::Module, obj::Obj,
@ -392,10 +391,7 @@ extern "C" fn new_confirm_homescreen(n_args: usize, args: *const Obj, kwargs: *m
let block = move |_args: &[Obj], kwargs: &Map| {
let title: TString = kwargs.get(Qstr::MP_QSTR_title)?.try_into()?;
let image: Obj = kwargs.get(Qstr::MP_QSTR_image)?;
let obj = LayoutObj::new(ConfirmHomescreen::new(
title,
BinaryData::from_object(image)?,
))?;
let obj = LayoutObj::new(ConfirmHomescreen::new(title, image.try_into()?))?;
Ok(obj.into())
};
@ -1600,7 +1596,7 @@ extern "C" fn new_confirm_firmware_update(
pub extern "C" fn upy_check_homescreen_format(data: Obj) -> Obj {
let block = || {
let image = BinaryData::from_object(data)?;
let image = data.try_into()?;
Ok(check_homescreen_format(image).into())
};

@ -568,7 +568,7 @@ fn get_homescreen_image() -> BinaryData<'static> {
return image;
}
}
BinaryData::from_slice(IMAGE_HOMESCREEN)
IMAGE_HOMESCREEN.into()
}
#[cfg(feature = "ui_debug")]

@ -615,12 +615,12 @@ extern "C" fn new_confirm_homescreen(n_args: usize, args: *const Obj, kwargs: *m
let title: TString = kwargs.get(Qstr::MP_QSTR_title)?.try_into()?;
let image: Obj = kwargs.get(Qstr::MP_QSTR_image)?;
let mut jpeg = BinaryData::from_object(image)?;
let mut jpeg: BinaryData = image.try_into()?;
if jpeg.is_empty() {
// Incoming data may be empty, meaning we should
// display default homescreen image.
jpeg = BinaryData::from_slice(theme::IMAGE_HOMESCREEN);
jpeg = theme::IMAGE_HOMESCREEN.into();
}
if !check_homescreen_format(jpeg, false) {
@ -1573,7 +1573,7 @@ extern "C" fn new_show_lockscreen(n_args: usize, args: *const Obj, kwargs: *mut
pub extern "C" fn upy_check_homescreen_format(data: Obj) -> Obj {
let block = || {
let buffer = BinaryData::from_object(data)?;
let buffer = data.try_into()?;
Ok(check_homescreen_format(buffer, false).into())
};

@ -46,7 +46,7 @@ impl<'a> JpegImage<'a> {
}
pub fn new(pos: Point, jpeg: &'a [u8]) -> Self {
Self::new_image(pos, BinaryData::from_slice(jpeg))
Self::new_image(pos, jpeg.into())
}
pub fn with_align(self, align: Alignment2D) -> Self {

@ -42,7 +42,7 @@ impl<'a> ToifImage<'a> {
Self {
pos,
align: Alignment2D::TOP_LEFT,
toif: BinaryData::from_slice(toif.original_data()),
toif: toif.original_data().into(),
fg_color: Color::white(),
bg_color: None,
size: Offset::zero(),

Loading…
Cancel
Save