Trouble finding an appropriate trait bound, what would you use?

⚓ Rust    📅 2026-01-20    👤 surdeus    👁️ 2      

surdeus

I'm using serde and not quite sure I should be, but the churn of using something else would be much worse.
Essentially, I'm trying to implement a wrapper type for a length-prefixed sequence as I have any combination of u8, u16, u32, VarInt, VarShort (which is neither var nor short) for length and String (would prefer &'de str), ByteString, ByteStr, Vec<u8>, &[u8] for the actual data.

Example usage I was aiming for:

#[packet(0, s2c)]
pub struct HandShakeS2C {
    pub protocol_version: VarInt,
    pub server_address: VarString, // 255
    pub server_port: u16,
    pub next_state: ConnectionState,
}

#[packet(0x01, s2c)]
pub struct EncryptionS2C<'a> {
    pub server_id: &'a str, // 20, also haven't figured out how to make a type for &str :(
    pub public_key: NetSlice<'a, u16, u8>,
    pub verify_token: NetSlice<'a, u16, u8>,
}

/// A String that encodes its length using a VarInt.
pub type VarString = NetList<VarInt, String, char>;

/// A slice that encodes its length using the specified length type.
pub type NetSlice<'a, I, T> = NetList<I, &'a [T], T>;

This may be a bit of an XY problem. If there is a better way, please let me know.

Here's what I came up with, my problem is that I can't find the appropriate bound to fit all these data collections. Some of them either don't implement AsRef<[Item]> (like String for AsRef<[char]> or Extend<Item> (like ByteString).

/// A list that encodes its length using the specified type.
#[derive(Debug, PartialEq)]
pub struct NetList<Len, Data, Item>(pub Data, PhantomData<Item>, PhantomData<Len>);

impl<L, D, I> NetList<L, D, I> {
    pub fn new(data: D) -> Self {
        Self(data, PhantomData::<I>, PhantomData::<L>)
    }
}

impl<L, D, I> Serialize for NetList<L, D, I>
where
    L: TryFrom<usize> + Default + Serialize,
    D: AsRef<[I]>,
    I: Serialize,
{
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
    where
        S: Serializer,
    {
        let iter = self.0.as_ref().into_iter();
        let (min, max) = iter.size_hint();
        let len = max.unwrap_or(min);
        let mut seq = serializer.serialize_tuple(len)?;
        seq.serialize_element(&L::try_from(len).unwrap_or(L::default()))?;
        for e in self.0.as_ref().into_iter() {
            seq.serialize_element(e)?;
        }
        seq.end()
    }
}

impl<'de, L, Data, I> Deserialize<'de> for NetList<L, Data, I>
where
    L: Deserialize<'de> + Into<usize>,
    Data: Default + Extend<I>,
    I: Deserialize<'de>,
{
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
    where
        D: Deserializer<'de>,
    {
        let data = deserializer.deserialize_newtype_struct(
            "[?; ?]",
            PrefixedCollectionVisitor(PhantomData::<L>, PhantomData::<Data>, PhantomData::<I>),
        )?;
        Ok(NetList(data, PhantomData::<I>, PhantomData::<L>))
    }
}

struct PrefixedCollectionVisitor<Len, Data, Item>(
    PhantomData<Len>,
    PhantomData<Data>,
    PhantomData<Item>,
);

impl<'de, I, Data, T> Visitor<'de> for PrefixedCollectionVisitor<I, Data, T>
where
    I: Deserialize<'de> + Into<usize>,
    Data: Default + Extend<T>,
    T: Deserialize<'de>,
{
    type Value = Data;

    fn expecting(&self, formatter: &mut Formatter) -> std::fmt::Result {
        write!(
            formatter,
            "a {}-prefixed list of {}",
            any::type_name::<I>(),
            any::type_name::<T>()
        )
    }

    fn visit_newtype_struct<D>(self, deserializer: D) -> Result<Self::Value, D::Error>
    where
        D: Deserializer<'de>,
    {
        deserializer.deserialize_seq(self)
    }

    fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
    where
        A: SeqAccess<'de>,
    {
        let prefix: I = seq.next_element()?.ok_or(A::Error::missing_field("len"))?;
        seq.next_element_seed(PrefixedCollectionSeed(
            prefix.into(),
            PhantomData::<I>,
            PhantomData::<Data>,
            PhantomData::<T>,
        ))?
        .ok_or(A::Error::missing_field("elements"))
    }
}

struct PrefixedCollectionSeed<I, D, T>(usize, PhantomData<I>, PhantomData<D>, PhantomData<T>);

impl<'de, I, Data, T> DeserializeSeed<'de> for PrefixedCollectionSeed<I, Data, T>
where
    I: Deserialize<'de>,
    Data: Default + Extend<T>,
    T: Deserialize<'de>,
{
    type Value = Data;

    fn deserialize<D>(self, deserializer: D) -> Result<Self::Value, D::Error>
    where
        D: Deserializer<'de>,
    {
        deserializer.deserialize_tuple_struct("NetList", self.0, self)
    }
}

impl<'de, I, Data, T> Visitor<'de> for PrefixedCollectionSeed<I, Data, T>
where
    I: Deserialize<'de>,
    Data: Default + Extend<T>,
    T: Deserialize<'de>,
{
    type Value = Data;

    fn expecting(&self, formatter: &mut Formatter) -> std::fmt::Result {
        write!(formatter, "a [{:?}; {}]", any::type_name::<T>(), self.0)
    }

    fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
    where
        A: SeqAccess<'de>,
    {
        let mut data = Data::default();
        data.extend_reserve(self.0);
        while let Some(next) = seq.next_element()? {
            data.extend_one(next);
        }
        Ok(data)
    }
}

1 post - 1 participant

Read full topic

🏷️ Rust_feed