rfcs icon indicating copy to clipboard operation
rfcs copied to clipboard

Match arrays against byte strings

Open Wicpar opened this issue 2 years ago • 7 comments

Hi,

Today i have to do this:

const MVHD: [u8;4] = *b"mvhd";
match header.id {
    BoxType::Id(BoxId(MVHD)) => self.mvhd = Some(MvhdBox::read(header, reader).await?),
    // Or
    BoxType::Id(BoxId([b'm', b'v', b'e', b'x'])) => self.mvex = Some(MvexBox::read(header, reader).await?),
    ...
}

When it would be reaonable and convenient to be able to do this:

match header.id {
    BoxType::Id(BoxId(b"mvhd")) => self.mvhd = Some(MvhdBox::read(header, reader).await?),
    BoxType::Id(BoxId(b"mvex")) => self.mvex = Some(MvexBox::read(header, reader).await?),
    ...
}

Today it gives:

BoxType::Id(BoxId(b"mvhd")) => self.mvhd = Some(MvhdBox::read(header, reader).await?),
                  ^^^^^^^ expected array `[u8; 4]`, found `&[u8; 4]`

Any plans on implementing a solution ?

Wicpar avatar Jul 13 '22 16:07 Wicpar

It will be at least easier with const blocks.

ChayimFriedman2 avatar Jul 13 '22 17:07 ChayimFriedman2

an elegant way to get around that is to use associated consts in this way:

pub trait PartialBox {
    const ID: BoxType;
}

impl PartialBox for MvhdBox {
    const ID: BoxType = BoxType::Id(BoxId(*b"mvhd"));
}

impl PartialBox for MvexBox {
    const ID: BoxType = BoxType::Id(BoxId(*b"mvex"));
}

// somewhere else

match header.id {
    MvhdBox::ID => self.mvhd = Some(MvhdBox::read(header, reader).await?),
    MvexBox::ID => self.mvex = Some(MvexBox::read(header, reader).await?),
    _ => {}
}

this issue is still relevant nonetheless

thanks @ChayimFriedman2, you gave me the idea mentioning consts

Wicpar avatar Jul 13 '22 17:07 Wicpar

I don't understand the issue; what's wrong with simply dereferencing the array?

match header.id {
    BoxType::Id(BoxId(*b"mvhd")) => self.mvhd = Some(MvhdBox::read(header, reader).await?),
    BoxType::Id(BoxId(*b"mvex")) => self.mvex = Some(MvexBox::read(header, reader).await?),
    ...
}

What you're doing is equivalent to passing &[b'm', b'v', b'e', b'x'] which is just erroneous?

vimirage avatar Jul 14 '22 02:07 vimirage

I don't understand the issue; what's wrong with simply dereferencing the array?

match header.id {
    BoxType::Id(BoxId(*b"mvhd")) => self.mvhd = Some(MvhdBox::read(header, reader).await?),
    BoxType::Id(BoxId(*b"mvex")) => self.mvex = Some(MvexBox::read(header, reader).await?),
    ...
}

Just that you can't do that.

ChayimFriedman2 avatar Jul 14 '22 04:07 ChayimFriedman2

Oh! I didn't think much of it being in a match position, that makes more sense. Got it.

vimirage avatar Jul 14 '22 04:07 vimirage

For cases where it doesn't make sense to use/have associated consts, I end up placing const values immediately above the match block, then matching against the const values. See

I've always wished the compiler could just do that for me, though. IMHO anything that can be stored as a local const variable and then matched against should be fair to match against directly (unless it causes an ambiguous parse, of course).

mqudsi avatar Jul 27 '22 16:07 mqudsi

Not very ergonomic, but it occurs to me that there's an RFC for inline const expressions, allowing:

match header.id {
    BoxType::Id(BoxId(const { *b"mvhd") }) => self.mvhd = Some(MvhdBox::read(header, reader).await?),
    BoxType::Id(BoxId(const { *b"mvex") }) => self.mvex = Some(MvexBox::read(header, reader).await?),
    ...
}

vimirage avatar Jul 27 '22 22:07 vimirage