use crate::binder::Stability;
use crate::error::{Result, StatusCode};
use crate::{
Deserialize, Parcel, Parcelable, ParcelableMetadata, Serialize, NON_NULL_PARCELABLE_FLAG,
NULL_PARCELABLE_FLAG,
};
use downcast_rs::{impl_downcast, DowncastSync};
use std::any::Any;
use std::sync::{Arc, Mutex};
trait AnyParcelable: DowncastSync + Parcelable + std::fmt::Debug {}
impl_downcast!(sync AnyParcelable);
impl<T> AnyParcelable for T where T: DowncastSync + Parcelable + std::fmt::Debug {}
#[derive(Debug)]
enum ParcelableHolderData {
Empty,
Parcelable {
parcelable: Arc<dyn AnyParcelable>,
name: String,
},
Parcel(Parcel),
}
#[derive(Debug)]
pub struct ParcelableHolder {
data: Mutex<ParcelableHolderData>,
stability: Stability,
}
impl Default for ParcelableHolder {
fn default() -> Self {
Self::new(Stability::Local)
}
}
impl ParcelableHolder {
pub fn new(stability: Stability) -> Self {
Self {
data: Mutex::new(ParcelableHolderData::Empty),
stability,
}
}
pub fn reset(&mut self) {
*self
.data
.get_mut()
.expect("Parcelable holder lock poisoned") = ParcelableHolderData::Empty;
}
pub fn set_parcelable<T>(&mut self, p: Arc<T>) -> Result<()>
where
T: Any + Parcelable + ParcelableMetadata + std::fmt::Debug + Send + Sync,
{
if !p.stability().includes(self.stability) {
log::error!(
"ParcelableHolder::set_parcelable: parcelable stability {:?} does not include holder stability {:?}",
p.stability(),
self.stability
);
return Err(StatusCode::BadValue);
}
*self
.data
.get_mut()
.expect("Parcelable holder lock poisoned") = ParcelableHolderData::Parcelable {
parcelable: p,
name: T::descriptor().into(),
};
Ok(())
}
pub fn get_parcelable<T>(&self) -> Result<Option<Arc<T>>>
where
T: Any + Parcelable + ParcelableMetadata + Default + std::fmt::Debug + Send + Sync,
{
let parcelable_desc = T::descriptor();
let mut data = self.data.lock().expect("Parcelable holder lock poisoned");
match *data {
ParcelableHolderData::Empty => Ok(None),
ParcelableHolderData::Parcelable {
ref parcelable,
ref name,
} => {
if name != parcelable_desc {
log::error!(
"ParcelableHolder::get_parcelable: parcelable descriptor mismatch: {name:?} != {parcelable_desc:?}");
return Err(StatusCode::BadValue);
}
match Arc::clone(parcelable).downcast_arc::<T>() {
Err(_) => {
log::error!("ParcelableHolder::get_parcelable: parcelable type mismatch: {parcelable:?} != {parcelable_desc:?}");
Err(StatusCode::BadValue)
}
Ok(x) => Ok(Some(x)),
}
}
ParcelableHolderData::Parcel(ref mut parcel) => {
parcel.set_data_position(0);
let name: String = parcel.read()?;
if name != parcelable_desc {
return Ok(None);
}
let mut parcelable = T::default();
parcelable.read_from_parcel(parcel)?;
let parcelable = Arc::new(parcelable);
let result = Arc::clone(&parcelable);
*data = ParcelableHolderData::Parcelable { parcelable, name };
Ok(Some(result))
}
}
}
pub fn get_stability(&self) -> Stability {
self.stability
}
}
impl Serialize for ParcelableHolder {
fn serialize(&self, parcel: &mut Parcel) -> Result<()> {
parcel.write(&NON_NULL_PARCELABLE_FLAG)?;
self.write_to_parcel(parcel)
}
}
impl Deserialize for ParcelableHolder {
fn deserialize(parcel: &mut Parcel) -> Result<Self> {
let status: i32 = parcel.read()?;
if status == NULL_PARCELABLE_FLAG {
log::error!("ParcelableHolder::deserialize: unexpected null");
Err(StatusCode::UnexpectedNull)
} else {
let mut parcelable = ParcelableHolder::default();
parcelable.read_from_parcel(parcel)?;
Ok(parcelable)
}
}
}
impl Parcelable for ParcelableHolder {
fn write_to_parcel(&self, parcel: &mut Parcel) -> Result<()> {
parcel.write(&(self.stability as i32))?;
let mut data = self.data.lock().expect("Parcelable holder lock poisoned");
match *data {
ParcelableHolderData::Empty => parcel.write(&0i32),
ParcelableHolderData::Parcelable {
ref parcelable,
ref name,
} => {
let length_start = parcel.data_position();
parcel.write(&0i32)?;
let data_start = parcel.data_position();
parcel.write(name)?;
parcelable.write_to_parcel(parcel)?;
let end = parcel.data_position();
parcel.set_data_position(length_start);
assert!(end >= data_start);
parcel.write(&((end - data_start) as i32))?;
parcel.set_data_position(end);
Ok(())
}
ParcelableHolderData::Parcel(ref mut p) => {
parcel.write(&(p.data_size() as i32))?;
parcel.append_all_from(p)
}
}
}
fn read_from_parcel(&mut self, parcel: &mut Parcel) -> Result<()> {
let wire_stability: i32 = parcel.read()?;
if self.stability as i32 != wire_stability {
log::error!(
"ParcelableHolder::read_from_parcel: parcelable stability mismatch: {:?} != {:?}",
self.stability,
wire_stability
);
return Err(StatusCode::BadValue);
}
let data_size: i32 = parcel.read()?;
if data_size < 0 {
return Err(StatusCode::BadValue);
}
if data_size == 0 {
*self
.data
.get_mut()
.expect("Parcelable holder lock poisoned") = ParcelableHolderData::Empty;
return Ok(());
}
let data_start: usize = parcel.data_position();
let data_end: usize = data_start
.checked_add(data_size as usize)
.ok_or(StatusCode::BadValue)?;
let mut new_parcel = Parcel::new();
new_parcel.append_from(parcel, data_start, data_size as usize)?;
*self
.data
.get_mut()
.expect("Parcelable holder lock poisoned") = ParcelableHolderData::Parcel(new_parcel);
parcel.set_data_position(data_end);
Ok(())
}
}