Skip to content

Commit

Permalink
support downcasting to concrete list and struct types
Browse files Browse the repository at this point in the history
  • Loading branch information
dwrensha committed Sep 23, 2024
1 parent 80d915a commit 37dffdd
Show file tree
Hide file tree
Showing 11 changed files with 354 additions and 4 deletions.
24 changes: 24 additions & 0 deletions capnp/src/data_list.rs
Original file line number Diff line number Diff line change
Expand Up @@ -215,6 +215,17 @@ impl<'a> From<Reader<'a>> for crate::dynamic_value::Reader<'a> {
}
}

impl<'a> crate::dynamic_value::DowncastReader<'a> for Reader<'a> {
fn downcast_reader(v: crate::dynamic_value::Reader<'a>) -> Self {
let dl: crate::dynamic_list::Reader = v.downcast();
assert_eq!(
dl.element_type(),
crate::introspect::TypeVariant::Data.into()
);
Reader { reader: dl.reader }
}
}

impl<'a> From<Builder<'a>> for crate::dynamic_value::Builder<'a> {
fn from(t: Builder<'a>) -> crate::dynamic_value::Builder<'a> {
crate::dynamic_value::Builder::List(crate::dynamic_list::Builder {
Expand All @@ -224,6 +235,19 @@ impl<'a> From<Builder<'a>> for crate::dynamic_value::Builder<'a> {
}
}

impl<'a> crate::dynamic_value::DowncastBuilder<'a> for Builder<'a> {
fn downcast_builder(v: crate::dynamic_value::Builder<'a>) -> Self {
let dl: crate::dynamic_list::Builder = v.downcast();
assert_eq!(
dl.element_type(),
crate::introspect::TypeVariant::Data.into()
);
Builder {
builder: dl.builder,
}
}
}

impl<'a> core::fmt::Debug for Reader<'a> {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
core::fmt::Debug::fmt(
Expand Down
6 changes: 3 additions & 3 deletions capnp/src/dynamic_struct.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ pub(crate) fn struct_size_from_schema(schema: StructSchema) -> Result<layout::St
#[derive(Clone, Copy)]
pub struct Reader<'a> {
pub(crate) reader: layout::StructReader<'a>,
schema: StructSchema,
pub(crate) schema: StructSchema,
}

impl<'a> From<Reader<'a>> for dynamic_value::Reader<'a> {
Expand Down Expand Up @@ -236,8 +236,8 @@ impl<'a> Reader<'a> {

/// A mutable dynamically-typed struct.
pub struct Builder<'a> {
builder: layout::StructBuilder<'a>,
schema: StructSchema,
pub(crate) builder: layout::StructBuilder<'a>,
pub(crate) schema: StructSchema,
}

impl<'a> From<Builder<'a>> for dynamic_value::Builder<'a> {
Expand Down
36 changes: 36 additions & 0 deletions capnp/src/dynamic_value.rs
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,24 @@ impl<'a> Reader<'a> {
pub fn downcast<T: DowncastReader<'a>>(self) -> T {
T::downcast_reader(self)
}

/// Downcasts the `Reader` into a specific struct type. Panics if the
/// expected type does not match the value.
///
/// Design note: instead of this method, it would be better to add a blanket impl
/// of the `DowncastBuilder` trait that covered every struct type. Unfortunately,
/// the current way the `Introspect` and `OwnedStruct` traits are set up does not
/// seem to allow this.
pub fn downcast_struct<T: crate::traits::OwnedStruct>(self) -> T::Reader<'a> {
let sr: dynamic_struct::Reader = self.downcast();
let TypeVariant::Struct(rs) = T::introspect().which() else {
panic!("not a struct");
};
if sr.schema.raw != rs {
panic!("tried to downcast to wrong struct type");
}
sr.reader.into()
}
}

impl<'a> From<()> for Reader<'a> {
Expand Down Expand Up @@ -215,6 +233,24 @@ impl<'a> Builder<'a> {
pub fn downcast<T: DowncastBuilder<'a>>(self) -> T {
T::downcast_builder(self)
}

/// Downcasts the `Builder` into a specific struct type. Panics if the
/// expected type does not match the value.
///
/// Design note: instead of this method, it would be better to add a blanket impl
/// of the `DowncastBuilder` trait that covered every struct type. Unfortunately,
/// the current way the `Introspect` and `OwnedStruct` traits are set up does not
/// seem to allow this.
pub fn downcast_struct<T: crate::traits::OwnedStruct>(self) -> T::Builder<'a> {
let sb: dynamic_struct::Builder = self.downcast();
let TypeVariant::Struct(rs) = T::introspect().which() else {
panic!("not a struct");
};
if sb.schema.raw != rs {
panic!("tried to downcast to wrong struct type");
}
sb.builder.into()
}
}

/// Helper trait for the `dynamic_value::Builder::downcast()` method.
Expand Down
26 changes: 26 additions & 0 deletions capnp/src/enum_list.rs
Original file line number Diff line number Diff line change
Expand Up @@ -255,6 +255,19 @@ impl<'a, T: TryFrom<u16, Error = NotInSchema> + crate::introspect::Introspect> F
}
}

impl<'a, T: TryFrom<u16, Error = NotInSchema> + crate::introspect::Introspect>
crate::dynamic_value::DowncastReader<'a> for Reader<'a, T>
{
fn downcast_reader(v: crate::dynamic_value::Reader<'a>) -> Self {
let dl: crate::dynamic_list::Reader = v.downcast();
assert_eq!(dl.element_type(), T::introspect());
Reader {
reader: dl.reader,
marker: PhantomData,
}
}
}

impl<'a, T: TryFrom<u16, Error = NotInSchema> + crate::introspect::Introspect> From<Builder<'a, T>>
for crate::dynamic_value::Builder<'a>
{
Expand All @@ -266,6 +279,19 @@ impl<'a, T: TryFrom<u16, Error = NotInSchema> + crate::introspect::Introspect> F
}
}

impl<'a, T: TryFrom<u16, Error = NotInSchema> + crate::introspect::Introspect>
crate::dynamic_value::DowncastBuilder<'a> for Builder<'a, T>
{
fn downcast_builder(v: crate::dynamic_value::Builder<'a>) -> Self {
let dl: crate::dynamic_list::Builder = v.downcast();
assert_eq!(dl.element_type(), T::introspect());
Builder {
builder: dl.builder,
marker: PhantomData,
}
}
}

impl<'a, T: Copy + TryFrom<u16, Error = NotInSchema> + crate::introspect::Introspect>
core::fmt::Debug for Reader<'a, T>
{
Expand Down
2 changes: 1 addition & 1 deletion capnp/src/introspect.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ pub trait Introspect {
/// optimized to avoid heap allocation.
///
/// To examine a `Type`, you should call the `which()` method.
#[derive(Copy, Clone, PartialEq, Eq)]
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub struct Type {
/// The type, minus any outer `List( )`.
base: BaseType,
Expand Down
22 changes: 22 additions & 0 deletions capnp/src/list_list.rs
Original file line number Diff line number Diff line change
Expand Up @@ -284,6 +284,17 @@ impl<'a, T: crate::traits::Owned> From<Reader<'a, T>> for crate::dynamic_value::
}
}

impl<'a, T: crate::traits::Owned> crate::dynamic_value::DowncastReader<'a> for Reader<'a, T> {
fn downcast_reader(v: crate::dynamic_value::Reader<'a>) -> Self {
let dl: crate::dynamic_list::Reader = v.downcast();
assert_eq!(dl.element_type(), T::introspect());
Reader {
reader: dl.reader,
marker: core::marker::PhantomData,
}
}
}

impl<'a, T: crate::traits::Owned> From<Builder<'a, T>> for crate::dynamic_value::Builder<'a> {
fn from(t: Builder<'a, T>) -> crate::dynamic_value::Builder<'a> {
crate::dynamic_value::Builder::List(crate::dynamic_list::Builder::new(
Expand All @@ -293,6 +304,17 @@ impl<'a, T: crate::traits::Owned> From<Builder<'a, T>> for crate::dynamic_value:
}
}

impl<'a, T: crate::traits::Owned> crate::dynamic_value::DowncastBuilder<'a> for Builder<'a, T> {
fn downcast_builder(v: crate::dynamic_value::Builder<'a>) -> Self {
let dl: crate::dynamic_list::Builder = v.downcast();
assert_eq!(dl.element_type(), T::introspect());
Builder {
builder: dl.builder,
marker: core::marker::PhantomData,
}
}
}

impl<'a, T: crate::traits::Owned> core::fmt::Debug for Reader<'a, T> {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
core::fmt::Debug::fmt(
Expand Down
26 changes: 26 additions & 0 deletions capnp/src/primitive_list.rs
Original file line number Diff line number Diff line change
Expand Up @@ -344,6 +344,19 @@ impl<'a, T: PrimitiveElement + crate::introspect::Introspect> From<Reader<'a, T>
}
}

impl<'a, T: PrimitiveElement + crate::introspect::Introspect>
crate::dynamic_value::DowncastReader<'a> for Reader<'a, T>
{
fn downcast_reader(v: crate::dynamic_value::Reader<'a>) -> Self {
let dl: crate::dynamic_list::Reader = v.downcast();
assert_eq!(dl.element_type(), T::introspect());
Reader {
reader: dl.reader,
marker: marker::PhantomData,
}
}
}

impl<'a, T: PrimitiveElement + crate::introspect::Introspect> From<Builder<'a, T>>
for crate::dynamic_value::Builder<'a>
{
Expand All @@ -355,6 +368,19 @@ impl<'a, T: PrimitiveElement + crate::introspect::Introspect> From<Builder<'a, T
}
}

impl<'a, T: PrimitiveElement + crate::introspect::Introspect>
crate::dynamic_value::DowncastBuilder<'a> for Builder<'a, T>
{
fn downcast_builder(v: crate::dynamic_value::Builder<'a>) -> Self {
let dl: crate::dynamic_list::Builder = v.downcast();
assert_eq!(dl.element_type(), T::introspect());
Builder {
builder: dl.builder,
marker: marker::PhantomData,
}
}
}

impl<'a, T: Copy + PrimitiveElement + crate::introspect::Introspect> core::fmt::Debug
for Reader<'a, T>
{
Expand Down
24 changes: 24 additions & 0 deletions capnp/src/struct_list.rs
Original file line number Diff line number Diff line change
Expand Up @@ -291,6 +291,17 @@ impl<'a, T: crate::traits::OwnedStruct> From<Reader<'a, T>> for crate::dynamic_v
}
}

impl<'a, T: crate::traits::OwnedStruct> crate::dynamic_value::DowncastReader<'a> for Reader<'a, T> {
fn downcast_reader(v: crate::dynamic_value::Reader<'a>) -> Self {
let dl: crate::dynamic_list::Reader = v.downcast();
assert_eq!(dl.element_type(), T::introspect());
Reader {
reader: dl.reader,
marker: PhantomData,
}
}
}

impl<'a, T: crate::traits::OwnedStruct> From<Builder<'a, T>> for crate::dynamic_value::Builder<'a> {
fn from(t: Builder<'a, T>) -> crate::dynamic_value::Builder<'a> {
crate::dynamic_value::Builder::List(crate::dynamic_list::Builder::new(
Expand All @@ -300,6 +311,19 @@ impl<'a, T: crate::traits::OwnedStruct> From<Builder<'a, T>> for crate::dynamic_
}
}

impl<'a, T: crate::traits::OwnedStruct> crate::dynamic_value::DowncastBuilder<'a>
for Builder<'a, T>
{
fn downcast_builder(v: crate::dynamic_value::Builder<'a>) -> Self {
let dl: crate::dynamic_list::Builder = v.downcast();
assert_eq!(dl.element_type(), T::introspect());
Builder {
builder: dl.builder,
marker: PhantomData,
}
}
}

impl<'a, T: crate::traits::OwnedStruct> core::fmt::Debug for Reader<'a, T> {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
core::fmt::Debug::fmt(
Expand Down
24 changes: 24 additions & 0 deletions capnp/src/text_list.rs
Original file line number Diff line number Diff line change
Expand Up @@ -250,6 +250,17 @@ impl<'a> From<Reader<'a>> for crate::dynamic_value::Reader<'a> {
}
}

impl<'a> crate::dynamic_value::DowncastReader<'a> for Reader<'a> {
fn downcast_reader(v: crate::dynamic_value::Reader<'a>) -> Self {
let dl: crate::dynamic_list::Reader = v.downcast();
assert_eq!(
dl.element_type(),
crate::introspect::TypeVariant::Text.into()
);
Reader { reader: dl.reader }
}
}

impl<'a> From<Builder<'a>> for crate::dynamic_value::Builder<'a> {
fn from(t: Builder<'a>) -> crate::dynamic_value::Builder<'a> {
crate::dynamic_value::Builder::List(crate::dynamic_list::Builder {
Expand All @@ -259,6 +270,19 @@ impl<'a> From<Builder<'a>> for crate::dynamic_value::Builder<'a> {
}
}

impl<'a> crate::dynamic_value::DowncastBuilder<'a> for Builder<'a> {
fn downcast_builder(v: crate::dynamic_value::Builder<'a>) -> Self {
let dl: crate::dynamic_list::Builder = v.downcast();
assert_eq!(
dl.element_type(),
crate::introspect::TypeVariant::Text.into()
);
Builder {
builder: dl.builder,
}
}
}

impl<'a> core::fmt::Debug for Reader<'a> {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
core::fmt::Debug::fmt(
Expand Down
Loading

0 comments on commit 37dffdd

Please sign in to comment.