use crate::context::{ReadContext, WriteContext};
use crate::error::Error;
use crate::resolver::{RefFlag, RefMode};
use crate::serializer::any::check_erased_target_type;
use crate::serializer::Serializer;
use crate::type_id::{self, TypeId};
use crate::types::UnknownCase;
use std::any::Any;
use std::sync::Arc;
#[doc(hidden)]
pub fn write_unknown_case_body(
context: &mut WriteContext,
unknown: &UnknownCase,
) -> Result<(), Error> {
if write_typed_unknown_case_body(context, unknown)? {
return Ok(());
}
<Arc<dyn Any + Send + Sync> as Serializer>::write(
unknown.value_arc(),
context,
RefMode::Tracking,
true,
)
}
fn write_typed_unknown_case_body(
context: &mut WriteContext,
unknown: &UnknownCase,
) -> Result<bool, Error> {
let type_id = unknown.type_id();
if type_id == type_id::UNKNOWN && unknown.downcast_ref::<()>().is_some() {
context.writer.write_i8(RefFlag::Null as i8);
return Ok(true);
}
if !has_typed_value(unknown) {
return Ok(false);
}
context.writer.write_i8(RefFlag::NotNullValue as i8);
context.writer.write_u8(type_id as u8);
match type_id {
type_id::BOOL => context
.writer
.write_bool(*unknown.downcast_ref::<bool>().unwrap()),
type_id::INT8 => context
.writer
.write_i8(*unknown.downcast_ref::<i8>().unwrap()),
type_id::INT16 => context
.writer
.write_i16(*unknown.downcast_ref::<i16>().unwrap()),
type_id::INT32 => context
.writer
.write_i32(*unknown.downcast_ref::<i32>().unwrap()),
type_id::VARINT32 => context
.writer
.write_var_i32(*unknown.downcast_ref::<i32>().unwrap()),
type_id::INT64 => context
.writer
.write_i64(*unknown.downcast_ref::<i64>().unwrap()),
type_id::VARINT64 => context
.writer
.write_var_i64(*unknown.downcast_ref::<i64>().unwrap()),
type_id::TAGGED_INT64 => context
.writer
.write_tagged_i64(*unknown.downcast_ref::<i64>().unwrap()),
type_id::UINT8 => context
.writer
.write_u8(*unknown.downcast_ref::<u8>().unwrap()),
type_id::UINT16 => context
.writer
.write_u16(*unknown.downcast_ref::<u16>().unwrap()),
type_id::UINT32 => context
.writer
.write_u32(*unknown.downcast_ref::<u32>().unwrap()),
type_id::VAR_UINT32 => context
.writer
.write_var_u32(*unknown.downcast_ref::<u32>().unwrap()),
type_id::UINT64 => context
.writer
.write_u64(*unknown.downcast_ref::<u64>().unwrap()),
type_id::VAR_UINT64 => context
.writer
.write_var_u64(*unknown.downcast_ref::<u64>().unwrap()),
type_id::TAGGED_UINT64 => context
.writer
.write_tagged_u64(*unknown.downcast_ref::<u64>().unwrap()),
_ => return Ok(false),
}
Ok(true)
}
fn has_typed_value(unknown: &UnknownCase) -> bool {
match unknown.type_id() {
type_id::BOOL => unknown.downcast_ref::<bool>().is_some(),
type_id::INT8 => unknown.downcast_ref::<i8>().is_some(),
type_id::INT16 => unknown.downcast_ref::<i16>().is_some(),
type_id::INT32 | type_id::VARINT32 => unknown.downcast_ref::<i32>().is_some(),
type_id::INT64 | type_id::VARINT64 | type_id::TAGGED_INT64 => {
unknown.downcast_ref::<i64>().is_some()
}
type_id::UINT8 => unknown.downcast_ref::<u8>().is_some(),
type_id::UINT16 => unknown.downcast_ref::<u16>().is_some(),
type_id::UINT32 | type_id::VAR_UINT32 => unknown.downcast_ref::<u32>().is_some(),
type_id::UINT64 | type_id::VAR_UINT64 | type_id::TAGGED_UINT64 => {
unknown.downcast_ref::<u64>().is_some()
}
_ => false,
}
}
#[doc(hidden)]
pub fn read_unknown_case_body(
context: &mut ReadContext,
case_id: u32,
) -> Result<UnknownCase, Error> {
let ref_flag = context.ref_reader.read_ref_flag(&mut context.reader)?;
match ref_flag {
RefFlag::Null => Ok(UnknownCase::new(case_id, ())),
RefFlag::Ref => {
let ref_id = context.ref_reader.read_ref_id(&mut context.reader)?;
let value = context
.ref_reader
.get_arc_ref::<dyn std::any::Any + Send + Sync>(ref_id)
.ok_or_else(|| {
Error::invalid_data(format!("UnknownCase ref {} not found", ref_id))
})?;
Ok(UnknownCase::from_runtime(
case_id,
TypeId::UNKNOWN as u32,
value,
))
}
RefFlag::NotNullValue | RefFlag::RefValue => {
let ref_id = if matches!(ref_flag, RefFlag::RefValue) {
Some(context.ref_reader.reserve_ref_id())
} else {
None
};
let type_info = context.read_any_type_info()?;
check_erased_target_type(&type_info)?;
let value = type_info.get_harness().read_arc_any(context, &type_info)?;
if let Some(ref_id) = ref_id {
context.ref_reader.store_arc_ref_at(ref_id, value.clone());
}
Ok(UnknownCase::from_runtime(
case_id,
type_info.get_type_id() as u32,
value,
))
}
}
}
impl Serializer for UnknownCase {
type Target = Self;
fn write(
value: &Self,
context: &mut WriteContext,
ref_mode: RefMode,
write_type_info: bool,
) -> Result<(), Error> {
let _ = ref_mode;
let _ = write_type_info;
write_unknown_case_body(context, value)
}
fn write_data(value: &Self, context: &mut WriteContext) -> Result<(), Error> {
write_unknown_case_body(context, value)
}
fn read(
context: &mut ReadContext,
ref_mode: RefMode,
read_type_info: bool,
) -> Result<Self, Error> {
let _ = ref_mode;
let _ = read_type_info;
read_unknown_case_body(context, 0)
}
fn read_data(context: &mut ReadContext) -> Result<Self, Error> {
read_unknown_case_body(context, 0)
}
fn default_value(_: &mut ReadContext) -> Result<Self, Error> {
Ok(UnknownCase::new(0, ()))
}
fn read_arc_any(context: &mut ReadContext) -> Result<Arc<dyn Any + Send + Sync>, Error> {
Ok(Arc::new(read_unknown_case_body(context, 0)?))
}
fn static_type_id() -> TypeId {
TypeId::UNKNOWN
}
}