Open vhdirk opened 1 month ago
You can do what you're trying to do as follows
use bin_proto::{BitRead, ByteOrder, ProtocolRead, Result, TaggedRead};
use std::collections::HashMap;
use std::fmt::Debug;
trait Variant {}
struct Container(Box<dyn Variant>);
type F = dyn Fn(&mut dyn BitRead, ByteOrder, &mut Ctx) -> Result<Box<dyn Variant>>;
struct Ctx<'a>(HashMap<u8, &'a F>);
impl<'a, Tag> TaggedRead<Tag, Ctx<'a>> for Container
where
Tag: TryInto<u8, Error: Debug>,
{
fn read(
read: &mut dyn BitRead,
byte_order: ByteOrder,
ctx: &mut Ctx<'a>,
tag: Tag,
) -> Result<Self> {
let tag = tag.try_into().unwrap();
let constructor = *ctx.0.get(&tag).unwrap();
let inner = constructor(read, byte_order, ctx)?;
Ok(Self(inner))
}
}
You could construct a ctx as follows
#[derive(ProtocolRead)]
struct ConcreteVariant;
impl Variant for ConcreteVariant {}
impl ConcreteVariant {
fn new<'a>(
read: &mut dyn BitRead,
byte_order: ByteOrder,
ctx: &mut Ctx<'a>,
) -> Result<Box<dyn Variant>> {
Ok(Box::new(<Self as ProtocolRead<_>>::read(
read, byte_order, ctx,
)?))
}
}
let mut ctx = Ctx(HashMap::from([(42, &ConcreteVariant::new as &F)]));
~The only issue I'll have to fix is that if you have a parent struct containing Container
, like so, you're unable to specify lifetime parameters for the context. I'll fix that soon~
#[derive(ProtocolRead)]
#[protocol(ctx = Ctx<'a>, ctx_generics('a))]
struct Root {
tag: u8
#[protocol(tag = tag)]
container: Container,
}
With release 0.6.0 you can now do what I described in my previous comment.
As mentioned in #2 , I'm working on a pretty elaborate binary protocol. It's been on a bit of a backburner for a while but recentlyI've been able to allocate some time for this again. And I've hit a bit of a roadblock with deku: The protocol I'm implementing is quite extensible. It defines a base set of configuration objects, but most applications will want to add their own configuration objects. I basically look at it as some kind of weird rpc system.
To implement my proof of concept, I was using enums to handle most of the known variations in the protocol. But since enums are by definition closed sets, I am now looking at dynamic dispatch. The goal would by to have something like (pseudo code):
I've been trying to figure this out with deku, but my main issue has thus far been that deku's DekuReader trait exposes the underlying reader type, which makes it very hard to have dynamic dispatch working at all. How I would pass the registry deep into the parsing is still an unknown.
So this got me looking at bin-proto again. And reading about the tagging system got me excited; it might even be a good match for my specific use-case.