use super::codec::{codec_read_type_info_static, codec_ref_mode, codec_write_type_info, Codec};
use crate::context::{ReadContext, WriteContext};
use crate::error::Error;
use crate::meta::FieldType;
use crate::resolver::{RefMode, TypeInfo, TypeResolver};
use crate::serializer::Serializer;
use crate::type_id::TypeId;
use std::cell::{Ref, RefCell};
use std::marker::PhantomData;
use std::rc::Rc;
pub struct RefCellCodec<T, C, const NULLABLE: bool, const TRACK_REF: bool>(PhantomData<(T, C)>);
#[inline(always)]
fn borrow_for_write<T>(value: &RefCell<T>) -> Result<Ref<'_, T>, Error> {
match value.try_borrow() {
Ok(value) => Ok(value),
Err(_) => Err(refcell_borrow_error()),
}
}
#[cold]
#[inline(never)]
fn refcell_borrow_error() -> Error {
Error::invalid_data("cannot serialize RefCell while it is mutably borrowed")
}
impl<T, C, const NULLABLE: bool, const TRACK_REF: bool> Serializer
for RefCellCodec<T, C, NULLABLE, TRACK_REF>
where
T: 'static,
C: Serializer<Target = T>,
{
type Target = RefCell<T>;
#[inline(always)]
fn reserved_space() -> usize {
C::reserved_space()
}
#[inline(always)]
fn write_data(value: &RefCell<T>, context: &mut WriteContext) -> Result<(), Error> {
let value = borrow_for_write(value)?;
C::write_data(&value, context)
}
#[inline(always)]
fn read_data(context: &mut ReadContext) -> Result<RefCell<T>, Error> {
Ok(RefCell::new(C::read_data(context)?))
}
#[inline(always)]
fn write(
value: &RefCell<T>,
context: &mut WriteContext,
ref_mode: RefMode,
write_type_info: bool,
) -> Result<(), Error> {
let value = borrow_for_write(value)?;
C::write(&value, context, ref_mode, write_type_info)
}
#[inline(always)]
fn write_type_info_value(
context: &mut WriteContext,
target_type_id: std::any::TypeId,
) -> Result<Rc<TypeInfo>, Error> {
C::write_type_info_value(context, target_type_id)
}
#[inline(always)]
fn write_with_type_info(
value: &RefCell<T>,
context: &mut WriteContext,
ref_mode: RefMode,
type_info: &Rc<TypeInfo>,
) -> Result<(), Error> {
let value = borrow_for_write(value)?;
C::write_with_type_info(&value, context, ref_mode, type_info)
}
#[inline(always)]
fn read(
context: &mut ReadContext,
ref_mode: RefMode,
read_type_info: bool,
) -> Result<RefCell<T>, Error> {
Ok(RefCell::new(C::read(context, ref_mode, read_type_info)?))
}
#[inline(always)]
fn read_with_type_info(
context: &mut ReadContext,
ref_mode: RefMode,
type_info: &Rc<TypeInfo>,
) -> Result<RefCell<T>, Error> {
Ok(RefCell::new(C::read_with_type_info(
context, ref_mode, type_info,
)?))
}
#[inline(always)]
fn default_value(context: &mut ReadContext) -> Result<RefCell<T>, Error> {
Ok(RefCell::new(C::default_value(context)?))
}
#[inline(always)]
fn write_type_info(context: &mut WriteContext) -> Result<(), Error> {
C::write_type_info(context)
}
#[inline(always)]
fn read_type_info(context: &mut ReadContext) -> Result<(), Error> {
C::read_type_info(context)
}
#[inline(always)]
fn static_type_id() -> TypeId {
C::static_type_id()
}
const IS_OPTIONAL: bool = C::IS_OPTIONAL;
const IS_POLYMORPHIC: bool = C::IS_POLYMORPHIC;
const IS_SHARED_REF: bool = C::IS_SHARED_REF;
const IS_WRAPPER: bool = true;
const REQUIRES_SCOPED_ACCESS: bool = true;
#[inline(always)]
fn is_none(value: &RefCell<T>) -> bool {
if !C::IS_OPTIONAL {
return false;
}
match value.try_borrow() {
Ok(value) => C::is_none(&value),
Err(_) => false,
}
}
#[inline(always)]
fn dynamic_type_id(value: &RefCell<T>) -> Result<Option<std::any::TypeId>, Error> {
let value = borrow_for_write(value)?;
C::dynamic_type_id(&value)
}
}
impl<T, C, const NULLABLE: bool, const TRACK_REF: bool> Codec<RefCell<T>>
for RefCellCodec<T, C, NULLABLE, TRACK_REF>
where
T: 'static,
C: Codec<T>,
{
#[inline(always)]
fn field_type(type_resolver: &TypeResolver) -> Result<FieldType, Error> {
let mut field_type = C::field_type(type_resolver)?;
field_type.nullable = NULLABLE;
field_type.track_ref = TRACK_REF;
Ok(field_type)
}
#[inline(always)]
fn field_reserved_space() -> usize {
C::field_reserved_space()
}
#[inline(always)]
fn write_field(value: &RefCell<T>, context: &mut WriteContext) -> Result<(), Error> {
Self::write_with_mode(
value,
context,
codec_ref_mode::<T, C, NULLABLE, TRACK_REF>(),
codec_write_type_info::<T, C>(context),
true,
)
}
#[inline(always)]
fn read_field(context: &mut ReadContext) -> Result<RefCell<T>, Error> {
<Self as Serializer>::read(
context,
codec_ref_mode::<T, C, NULLABLE, TRACK_REF>(),
codec_read_type_info_static::<T, C>(context),
)
}
#[inline(always)]
fn read_data_with_type(
context: &mut ReadContext,
remote_data_type: &FieldType,
) -> Result<RefCell<T>, Error> {
Ok(RefCell::new(C::read_data_with_type(
context,
remote_data_type,
)?))
}
#[inline(always)]
fn read_field_with_type(
context: &mut ReadContext,
remote_field_type: &FieldType,
) -> Result<RefCell<T>, Error> {
Ok(RefCell::new(C::read_field_with_type(
context,
remote_field_type,
)?))
}
#[inline(always)]
fn write_with_mode(
value: &RefCell<T>,
context: &mut WriteContext,
ref_mode: RefMode,
write_type_info: bool,
has_generics: bool,
) -> Result<(), Error> {
let value = borrow_for_write(value)?;
C::write_with_mode(&value, context, ref_mode, write_type_info, has_generics)
}
#[inline(always)]
fn write_with_type_info(
value: &RefCell<T>,
context: &mut WriteContext,
ref_mode: RefMode,
type_info: &Rc<TypeInfo>,
has_generics: bool,
) -> Result<(), Error> {
let value = borrow_for_write(value)?;
<C as Codec<T>>::write_with_type_info(&value, context, ref_mode, type_info, has_generics)
}
#[inline(always)]
fn read_type_info_value(
context: &mut ReadContext,
) -> Result<super::codec::CodecReadType, Error> {
C::read_type_info_value(context)
}
}
impl_single_carrier_serializer!(RefCellSerializer, RefCell, RefCellCodec, wrapper = true);