use basalt_types::{Encode, EncodedSize, Result, VarInt};
#[derive(Debug, Clone, PartialEq)]
pub enum IDSet {
Tag(String),
Ids(Vec<i32>),
}
impl Encode for IDSet {
fn encode(&self, buf: &mut Vec<u8>) -> Result<()> {
match self {
Self::Tag(name) => {
VarInt(0).encode(buf)?;
name.encode(buf)
}
Self::Ids(ids) => {
VarInt((ids.len() as i32) + 1).encode(buf)?;
for id in ids {
VarInt(*id).encode(buf)?;
}
Ok(())
}
}
}
}
impl EncodedSize for IDSet {
fn encoded_size(&self) -> usize {
match self {
Self::Tag(name) => VarInt(0).encoded_size() + name.encoded_size(),
Self::Ids(ids) => {
VarInt((ids.len() as i32) + 1).encoded_size()
+ ids
.iter()
.map(|id| VarInt(*id).encoded_size())
.sum::<usize>()
}
}
}
}
#[cfg(test)]
mod tests {
use super::*;
fn roundtrip<T: Encode + EncodedSize>(value: &T) -> Vec<u8> {
let mut buf = Vec::new();
value.encode(&mut buf).expect("encode");
assert_eq!(
buf.len(),
value.encoded_size(),
"encoded_size disagrees with encode output length"
);
buf
}
#[test]
fn id_set_tag_round_trip() {
let set = IDSet::Tag("minecraft:planks".into());
let bytes = roundtrip(&set);
let mut expected = vec![0x00, 16];
expected.extend_from_slice(b"minecraft:planks");
assert_eq!(bytes, expected);
}
#[test]
fn id_set_ids_writes_offset_tag() {
let set = IDSet::Ids(vec![1, 2, 3]);
let bytes = roundtrip(&set);
assert_eq!(bytes, vec![0x04, 0x01, 0x02, 0x03]);
}
#[test]
fn id_set_empty_ids_uses_tag_one() {
let set = IDSet::Ids(vec![]);
let bytes = roundtrip(&set);
assert_eq!(bytes, vec![0x01]);
}
}