1
0
Fork 0
mirror of https://codeberg.org/demostf/parser.git synced 2026-06-03 18:24:05 +02:00

some write progress

This commit is contained in:
Robin Appelman 2021-07-13 20:42:59 +02:00
commit 9a9bcdc9df
18 changed files with 286 additions and 90 deletions

4
Cargo.lock generated
View file

@ -80,8 +80,6 @@ dependencies = [
[[package]] [[package]]
name = "bitbuffer" name = "bitbuffer"
version = "0.8.1" version = "0.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3ec331c3602bf9f2fde16a85cb3ddf13219f9653ee55c18948ff4418c85cfbb0"
dependencies = [ dependencies = [
"bitbuffer_derive", "bitbuffer_derive",
"err-derive 0.2.4", "err-derive 0.2.4",
@ -92,8 +90,6 @@ dependencies = [
[[package]] [[package]]
name = "bitbuffer_derive" name = "bitbuffer_derive"
version = "0.8.0" version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7f51dcbe693d21078994abd2afac5adc9bcc80fbdf80206ebdb33fec4a145693"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",

View file

@ -21,7 +21,7 @@ name = "loop"
path = "src/bin/loop.rs" path = "src/bin/loop.rs"
[dependencies] [dependencies]
bitbuffer = "0.8.1" bitbuffer = { version = "0.8", path = "../../bitbuffer" }
num_enum = "0.5" num_enum = "0.5"
num-traits = "0.2" num-traits = "0.2"
enumflags2 = "0.7" enumflags2 = "0.7"

View file

@ -1,4 +1,4 @@
use bitbuffer::BitRead; use bitbuffer::{BitRead, BitWrite};
use crate::{ParseError, Result}; use crate::{ParseError, Result};
@ -41,7 +41,7 @@ pub struct GameEventEntry {
pub kind: GameEventValueType, pub kind: GameEventValueType,
} }
#[derive(BitRead, Debug, Clone, Copy, PartialEq, Display)] #[derive(BitRead, BitWrite, Debug, Clone, Copy, PartialEq, Display)]
#[discriminant_bits = 3] #[discriminant_bits = 3]
pub enum GameEventValueType { pub enum GameEventValueType {
None = 0, None = 0,

View file

@ -1,6 +1,6 @@
use bitbuffer::BitRead; use bitbuffer::{BitRead, BitWrite};
#[derive(BitRead, Debug, PartialEq)] #[derive(BitRead, BitWrite, Debug, PartialEq)]
pub struct Header { pub struct Header {
#[size = 8] #[size = 8]
pub demo_type: String, pub demo_type: String,

View file

@ -1,10 +1,10 @@
use bitbuffer::{BitRead, LittleEndian}; use bitbuffer::{BitRead, BitWrite, BitWriteSized, BitWriteStream, LittleEndian};
use crate::demo::sendprop::read_bit_coord; use crate::demo::sendprop::{read_bit_coord, write_bit_coord};
use crate::demo::vector::Vector; use crate::demo::vector::Vector;
use crate::{ReadResult, Stream}; use crate::{ReadResult, Stream};
#[derive(Debug, Clone)] #[derive(Debug, Clone, PartialEq)]
pub struct BSPDecalMessage { pub struct BSPDecalMessage {
pub position: Vector, pub position: Vector,
pub texture_index: u16, pub texture_index: u16,
@ -16,9 +16,7 @@ pub struct BSPDecalMessage {
impl BitRead<'_, LittleEndian> for BSPDecalMessage { impl BitRead<'_, LittleEndian> for BSPDecalMessage {
fn read(stream: &mut Stream) -> ReadResult<Self> { fn read(stream: &mut Stream) -> ReadResult<Self> {
let position = { let position = {
let has_x = stream.read()?; let (has_x, has_y, has_z) = stream.read()?;
let has_y = stream.read()?;
let has_z = stream.read()?;
Vector { Vector {
x: if has_x { read_bit_coord(stream)? } else { 0f32 }, x: if has_x { read_bit_coord(stream)? } else { 0f32 },
@ -44,3 +42,55 @@ impl BitRead<'_, LittleEndian> for BSPDecalMessage {
}) })
} }
} }
impl BitWrite<LittleEndian> for BSPDecalMessage {
fn write(&self, stream: &mut BitWriteStream<LittleEndian>) -> ReadResult<()> {
let has_x = self.position.x != 0.0;
let has_y = self.position.y != 0.0;
let has_z = self.position.z != 0.0;
(has_x, has_y, has_z).write(stream)?;
if has_x {
write_bit_coord(self.position.x, stream)?;
}
if has_y {
write_bit_coord(self.position.y, stream)?;
}
if has_z {
write_bit_coord(self.position.z, stream)?;
}
self.texture_index.write_sized(stream, 9)?;
if self.ent_index != 0 || self.model_index != 0 {
true.write(stream)?;
self.ent_index.write_sized(stream, 12)?;
self.model_index.write_sized(stream, 12)?;
} else {
false.write(stream)?;
}
self.low_priority.write(stream)?;
Ok(())
}
}
#[test]
fn test_decal_roundtrip() {
crate::test_roundtrip_encode(BSPDecalMessage {
position: Vector::default(),
texture_index: 0,
ent_index: 0,
model_index: 0,
low_priority: false,
});
crate::test_roundtrip_encode(BSPDecalMessage {
position: Vector {
x: 1.0,
y: 0.5,
z: 0.0,
},
texture_index: 12,
ent_index: 15,
model_index: 2,
low_priority: true,
});
}

View file

@ -1,38 +1,38 @@
use crate::Stream; use crate::Stream;
/// Messages that consists only of primitives and string and can be derived /// Messages that consists only of primitives and string and can be derived
use bitbuffer::{BitRead, LittleEndian}; use bitbuffer::{BitRead, BitWrite, LittleEndian};
#[derive(BitRead, Debug)] #[derive(BitRead, BitWrite, Debug)]
pub struct FileMessage { pub struct FileMessage {
pub transfer_id: u32, pub transfer_id: u32,
pub file_name: String, pub file_name: String,
pub requested: bool, pub requested: bool,
} }
#[derive(BitRead, Debug)] #[derive(BitRead, BitWrite, Debug)]
pub struct NetTickMessage { pub struct NetTickMessage {
pub tick: u32, pub tick: u32,
pub frame_time: u16, pub frame_time: u16,
pub std_dev: u16, pub std_dev: u16,
} }
#[derive(BitRead, Debug)] #[derive(BitRead, BitWrite, Debug)]
pub struct StringCmdMessage { pub struct StringCmdMessage {
pub command: String, pub command: String,
} }
#[derive(BitRead, Debug)] #[derive(BitRead, BitWrite, Debug)]
pub struct SigOnStateMessage { pub struct SigOnStateMessage {
pub state: u8, pub state: u8,
pub count: u32, pub count: u32,
} }
#[derive(BitRead, Debug)] #[derive(BitRead, BitWrite, Debug)]
pub struct PrintMessage { pub struct PrintMessage {
pub value: String, pub value: String,
} }
#[derive(BitRead, Debug)] #[derive(BitRead, BitWrite, Debug)]
pub struct ServerInfoMessage { pub struct ServerInfoMessage {
pub version: u16, pub version: u16,
pub server_count: u32, pub server_count: u32,
@ -53,18 +53,18 @@ pub struct ServerInfoMessage {
pub replay: bool, pub replay: bool,
} }
#[derive(BitRead, Debug)] #[derive(BitRead, BitWrite, Debug)]
pub struct SetPauseMessage { pub struct SetPauseMessage {
pub pause: bool, pub pause: bool,
} }
#[derive(BitRead, Debug)] #[derive(BitRead, BitWrite, Debug)]
pub struct SetViewMessage { pub struct SetViewMessage {
#[size = 11] #[size = 11]
pub index: u16, pub index: u16,
} }
#[derive(BitRead, Debug)] #[derive(BitRead, BitWrite, Debug)]
pub struct FixAngleMessage { pub struct FixAngleMessage {
pub relative: bool, pub relative: bool,
pub x: u16, pub x: u16,
@ -72,7 +72,7 @@ pub struct FixAngleMessage {
pub z: u16, pub z: u16,
} }
#[derive(BitRead, Debug)] #[derive(BitRead, BitWrite, Debug)]
#[endianness = "LittleEndian"] #[endianness = "LittleEndian"]
pub struct EntityMessage<'a> { pub struct EntityMessage<'a> {
#[size = 11] #[size = 11]
@ -85,13 +85,13 @@ pub struct EntityMessage<'a> {
pub data: Stream<'a>, pub data: Stream<'a>,
} }
#[derive(BitRead, Debug)] #[derive(BitRead, BitWrite, Debug)]
pub struct PreFetchMessage { pub struct PreFetchMessage {
#[size = 14] #[size = 14]
pub index: u16, pub index: u16,
} }
#[derive(BitRead, Debug)] #[derive(BitRead, BitWrite, Debug)]
#[endianness = "LittleEndian"] #[endianness = "LittleEndian"]
pub struct MenuMessage<'a> { pub struct MenuMessage<'a> {
pub kind: u16, pub kind: u16,
@ -100,13 +100,13 @@ pub struct MenuMessage<'a> {
pub index: Stream<'a>, pub index: Stream<'a>,
} }
#[derive(BitRead, Debug)] #[derive(BitRead, BitWrite, Debug)]
pub struct GetCvarValueMessage { pub struct GetCvarValueMessage {
pub cookie: u32, pub cookie: u32,
pub value: String, pub value: String,
} }
#[derive(BitRead, Debug)] #[derive(BitRead, BitWrite, Debug)]
#[endianness = "LittleEndian"] #[endianness = "LittleEndian"]
pub struct CmdKeyValuesMessage<'a> { pub struct CmdKeyValuesMessage<'a> {
pub length: u32, pub length: u32,

View file

@ -1,8 +1,8 @@
use bitbuffer::{BitRead, LittleEndian}; use bitbuffer::{BitRead, BitWrite, BitWriteStream, LittleEndian};
use crate::{ReadResult, Stream}; use crate::{ReadResult, Stream};
#[derive(Debug, Clone)] #[derive(Debug, Clone, PartialEq)]
pub struct VoiceInitMessage { pub struct VoiceInitMessage {
codec: String, codec: String,
quality: u8, quality: u8,
@ -30,7 +30,34 @@ impl BitRead<'_, LittleEndian> for VoiceInitMessage {
} }
} }
#[derive(BitRead, Debug, Clone)] impl BitWrite<LittleEndian> for VoiceInitMessage {
fn write(&self, stream: &mut BitWriteStream<LittleEndian>) -> ReadResult<()> {
self.codec.write(stream)?;
self.quality.write(stream)?;
if self.quality == 255 {
self.sampling_rate.write(stream)?;
}
Ok(())
}
}
#[test]
fn test_voice_init_roundtrip() {
crate::test_roundtrip_encode(VoiceInitMessage {
codec: "foo".into(),
quality: 0,
sampling_rate: 0,
});
crate::test_roundtrip_encode(VoiceInitMessage {
codec: "foo".into(),
quality: 255,
sampling_rate: 12,
});
}
#[derive(BitRead, BitWrite, Debug, Clone)]
#[endianness = "LittleEndian"] #[endianness = "LittleEndian"]
pub struct VoiceDataMessage<'a> { pub struct VoiceDataMessage<'a> {
client: u8, client: u8,

View file

@ -1,4 +1,4 @@
use bitbuffer::{BitRead, LittleEndian}; use bitbuffer::{BitRead, BitWrite, BitWriteSized, LittleEndian};
use crate::{ReadResult, Stream}; use crate::{ReadResult, Stream};
@ -17,3 +17,13 @@ impl BitRead<'_, LittleEndian> for ConsoleCmdPacket {
Ok(ConsoleCmdPacket { tick, command }) Ok(ConsoleCmdPacket { tick, command })
} }
} }
impl BitWrite<LittleEndian> for ConsoleCmdPacket {
fn write(&self, stream: &mut bitbuffer::BitWriteStream<LittleEndian>) -> ReadResult<()> {
self.tick.write(stream)?;
let len = self.command.len() as u32;
len.write(stream)?;
self.command.write_sized(stream, len as usize)?;
Ok(())
}
}

View file

@ -1,4 +1,4 @@
use bitbuffer::BitRead; use bitbuffer::{BitRead, BitWrite};
use crate::demo::parser::MalformedSendPropDefinitionError; use crate::demo::parser::MalformedSendPropDefinitionError;
use crate::demo::sendprop::{ use crate::demo::sendprop::{
@ -11,9 +11,10 @@ use serde::{Deserialize, Serialize};
use std::cmp::min; use std::cmp::min;
use std::convert::TryFrom; use std::convert::TryFrom;
use std::rc::Rc;
#[derive(BitRead, Debug, Clone, Copy, PartialEq, Eq, Hash, Ord, PartialOrd, Display, FromStr)] #[derive(
BitRead, BitWrite, Debug, Clone, Copy, PartialEq, Eq, Hash, Ord, PartialOrd, Display, FromStr,
)]
pub struct ClassId(u16); pub struct ClassId(u16);
impl From<u16> for ClassId { impl From<u16> for ClassId {
@ -28,8 +29,8 @@ impl From<ClassId> for usize {
} }
} }
#[derive(BitRead, PartialEq, Eq, Hash, Debug, Serialize, Deserialize, Clone, Display)] #[derive(BitRead, BitWrite, PartialEq, Eq, Hash, Debug, Serialize, Deserialize, Clone, Display)]
pub struct ServerClassName(Rc<String>); pub struct ServerClassName(String);
impl ServerClassName { impl ServerClassName {
pub fn as_str(&self) -> &str { pub fn as_str(&self) -> &str {
@ -39,11 +40,11 @@ impl ServerClassName {
impl From<String> for ServerClassName { impl From<String> for ServerClassName {
fn from(value: String) -> Self { fn from(value: String) -> Self {
Self(Rc::new(value)) Self(value)
} }
} }
#[derive(BitRead, Debug, Clone)] #[derive(BitRead, BitWrite, Debug, Clone)]
pub struct ServerClass { pub struct ServerClass {
pub id: ClassId, pub id: ClassId,
pub name: ServerClassName, pub name: ServerClassName,
@ -52,6 +53,7 @@ pub struct ServerClass {
#[derive( #[derive(
BitRead, BitRead,
BitWrite,
PartialEq, PartialEq,
Eq, Eq,
Hash, Hash,
@ -64,7 +66,7 @@ pub struct ServerClass {
Ord, Ord,
Default, Default,
)] )]
pub struct SendTableName(Rc<String>); pub struct SendTableName(String);
impl SendTableName { impl SendTableName {
pub fn as_str(&self) -> &str { pub fn as_str(&self) -> &str {
@ -74,7 +76,7 @@ impl SendTableName {
impl From<String> for SendTableName { impl From<String> for SendTableName {
fn from(value: String) -> Self { fn from(value: String) -> Self {
Self(Rc::new(value)) Self(value)
} }
} }

View file

@ -1,11 +1,11 @@
use bitbuffer::{bit_size_of, BitRead, Endianness, LazyBitRead, LittleEndian}; use bitbuffer::{bit_size_of, BitRead, BitWrite, Endianness, LazyBitRead, LittleEndian};
use crate::demo::message::{Message, MessageType}; use crate::demo::message::{Message, MessageType};
use crate::demo::vector::Vector; use crate::demo::vector::Vector;
use crate::{Parse, ParserState, ReadResult, Result, Stream}; use crate::{Parse, ParserState, ReadResult, Result, Stream};
use std::fmt; use std::fmt;
#[derive(Debug, BitRead)] #[derive(Debug, BitRead, BitWrite)]
pub struct MessagePacketMeta { pub struct MessagePacketMeta {
pub flags: u32, // TODO pub flags: u32, // TODO
pub view_angles: ViewAngles, pub view_angles: ViewAngles,
@ -20,7 +20,7 @@ pub struct MessagePacket<'a> {
pub meta: LazyBitRead<'a, MessagePacketMeta, LittleEndian>, pub meta: LazyBitRead<'a, MessagePacketMeta, LittleEndian>,
} }
#[derive(Clone, Debug)] #[derive(Clone, Debug, PartialEq)]
pub struct ViewAngles { pub struct ViewAngles {
pub origin: (Vector, Vector), pub origin: (Vector, Vector),
pub angles: (Vector, Vector), pub angles: (Vector, Vector),
@ -29,12 +29,10 @@ pub struct ViewAngles {
impl<E: Endianness> BitRead<'_, E> for ViewAngles { impl<E: Endianness> BitRead<'_, E> for ViewAngles {
fn read(stream: &mut bitbuffer::BitReadStream<E>) -> ReadResult<Self> { fn read(stream: &mut bitbuffer::BitReadStream<E>) -> ReadResult<Self> {
let view_origin_1 = Vector::read(stream)?; let vectors = <[Vector; 6]>::read(stream)?;
let view_angle_1 = Vector::read(stream)?; let origin = (vectors[3], vectors[0]);
let local_view_angle_1 = Vector::read(stream)?; let angles = (vectors[4], vectors[1]);
let origin = (Vector::read(stream)?, view_origin_1); let local_angles = (vectors[5], vectors[2]);
let angles = (Vector::read(stream)?, view_angle_1);
let local_angles = (Vector::read(stream)?, local_view_angle_1);
Ok(ViewAngles { Ok(ViewAngles {
origin, origin,
angles, angles,
@ -47,6 +45,67 @@ impl<E: Endianness> BitRead<'_, E> for ViewAngles {
} }
} }
impl<E: Endianness> BitWrite<E> for ViewAngles {
fn write(&self, stream: &mut bitbuffer::BitWriteStream<E>) -> ReadResult<()> {
[
self.origin.1,
self.angles.1,
self.local_angles.1,
self.origin.0,
self.angles.0,
self.local_angles.0,
]
.write(stream)
}
}
#[test]
fn test_view_angles_roundtrip() {
crate::test_roundtrip_encode(ViewAngles {
origin: (Vector::default(), Vector::default()),
angles: (Vector::default(), Vector::default()),
local_angles: (Vector::default(), Vector::default()),
});
crate::test_roundtrip_encode(ViewAngles {
origin: (
Vector {
x: 1.0,
y: 1.0,
z: 1.0,
},
Vector {
x: 2.0,
y: 2.0,
z: 2.0,
},
),
angles: (
Vector {
x: 3.0,
y: 3.0,
z: 3.0,
},
Vector {
x: 4.0,
y: 4.0,
z: 4.0,
},
),
local_angles: (
Vector {
x: 5.0,
y: 5.0,
z: 5.0,
},
Vector {
x: 6.0,
y: 6.0,
z: 6.0,
},
),
});
}
impl<'a> Parse<'a> for MessagePacket<'a> { impl<'a> Parse<'a> for MessagePacket<'a> {
fn parse(stream: &mut Stream<'a>, _state: &ParserState) -> Result<Self> { fn parse(stream: &mut Stream<'a>, _state: &ParserState) -> Result<Self> {
let tick = stream.read()?; let tick = stream.read()?;

View file

@ -1,4 +1,4 @@
use bitbuffer::BitRead; use bitbuffer::{BitRead, BitWrite};
use num_enum::TryFromPrimitive; use num_enum::TryFromPrimitive;
use crate::{Parse, ParserState, Result, Stream}; use crate::{Parse, ParserState, Result, Stream};
@ -25,13 +25,13 @@ pub enum Packet<'a> {
Message(MessagePacket<'a>), Message(MessagePacket<'a>),
SyncTick(SyncTickPacket), SyncTick(SyncTickPacket),
ConsoleCmd(ConsoleCmdPacket), ConsoleCmd(ConsoleCmdPacket),
UserCmd(UserCmdPacket), UserCmd(UserCmdPacket<'a>),
DataTables(DataTablePacket), DataTables(DataTablePacket),
Stop(StopPacket), Stop(StopPacket),
StringTables(StringTablePacket<'a>), StringTables(StringTablePacket<'a>),
} }
#[derive(BitRead, TryFromPrimitive, Debug, Clone, Copy)] #[derive(BitRead, BitWrite, TryFromPrimitive, Debug, Clone, Copy)]
#[discriminant_bits = 8] #[discriminant_bits = 8]
#[repr(u8)] #[repr(u8)]
pub enum PacketType { pub enum PacketType {

View file

@ -1,12 +1,4 @@
use bitbuffer::{BitRead, LittleEndian}; use bitbuffer::{BitRead, BitWrite};
use crate::{ReadResult, Stream}; #[derive(Debug, BitRead, BitWrite)]
#[derive(Debug)]
pub struct StopPacket; pub struct StopPacket;
impl BitRead<'_, LittleEndian> for StopPacket {
fn read(_stream: &mut Stream) -> ReadResult<Self> {
Ok(StopPacket)
}
}

View file

@ -1,13 +1,13 @@
use std::fmt; use std::fmt;
use bitbuffer::{BitRead, LittleEndian}; use bitbuffer::{BitRead, BitWrite, LittleEndian};
use crate::demo::message::stringtable::StringTableMeta; use crate::demo::message::stringtable::StringTableMeta;
use crate::{Parse, ParseError, ParserState, ReadResult, Result, Stream}; use crate::{Parse, ParseError, ParserState, ReadResult, Result, Stream};
use std::borrow::{Borrow, Cow}; use std::borrow::{Borrow, Cow};
use std::cmp::min; use std::cmp::min;
#[derive(BitRead, Clone, Copy, Debug)] #[derive(BitRead, BitWrite, Clone, Copy, Debug)]
pub struct FixedUserDataSize { pub struct FixedUserDataSize {
#[size = 12] #[size = 12]
pub size: u16, pub size: u16,
@ -62,7 +62,7 @@ impl<'a> BitRead<'a, LittleEndian> for StringTable<'a> {
} }
} }
#[derive(BitRead, Clone, Debug)] #[derive(BitRead, BitWrite, Clone, Debug)]
#[endianness = "LittleEndian"] #[endianness = "LittleEndian"]
pub struct ExtraData<'a> { pub struct ExtraData<'a> {
pub byte_len: u16, pub byte_len: u16,

View file

@ -1,6 +1,6 @@
use bitbuffer::BitRead; use bitbuffer::{BitRead, BitWrite};
#[derive(BitRead, Debug)] #[derive(BitRead, BitWrite, Debug)]
pub struct SyncTickPacket { pub struct SyncTickPacket {
pub tick: u32, pub tick: u32,
} }

View file

@ -1,20 +1,12 @@
use bitbuffer::{BitRead, LittleEndian}; use crate::Stream;
use bitbuffer::{BitRead, BitWrite, LittleEndian};
use crate::{ReadResult, Stream}; #[derive(Debug, BitRead, BitWrite)]
#[endianness = "LittleEndian"]
#[derive(Debug)] pub struct UserCmdPacket<'a> {
pub struct UserCmdPacket {
tick: u32, tick: u32,
sequence_out: u32, sequence_out: u32,
} len: u32,
#[size = "len.saturating_mul(8)"]
impl BitRead<'_, LittleEndian> for UserCmdPacket { data: Stream<'a>,
fn read(stream: &mut Stream) -> ReadResult<Self> {
let tick = stream.read()?;
let sequence_out = stream.read()?;
let len: u32 = stream.read()?;
stream.skip_bits(len as usize * 8)?;
// TODO parse the packet data
Ok(UserCmdPacket { tick, sequence_out })
}
} }

View file

@ -1,4 +1,4 @@
use bitbuffer::{BitRead, LittleEndian}; use bitbuffer::{BitRead, BitWrite, BitWriteSized, BitWriteStream, LittleEndian};
use enumflags2::{bitflags, BitFlags}; use enumflags2::{bitflags, BitFlags};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
@ -10,6 +10,7 @@ use crate::consthash::ConstFnvHash;
use crate::demo::message::stringtable::log_base2; use crate::demo::message::stringtable::log_base2;
use crate::demo::packet::datatable::SendTableName; use crate::demo::packet::datatable::SendTableName;
use crate::demo::parser::MalformedSendPropDefinitionError; use crate::demo::parser::MalformedSendPropDefinitionError;
use num_traits::Signed;
use parse_display::Display; use parse_display::Display;
use std::cmp::min; use std::cmp::min;
use std::convert::{TryFrom, TryInto}; use std::convert::{TryFrom, TryInto};
@ -816,6 +817,52 @@ pub fn read_bit_coord(stream: &mut Stream) -> ReadResult<f32> {
}) })
} }
pub fn write_bit_coord(val: f32, stream: &mut BitWriteStream<LittleEndian>) -> ReadResult<()> {
let has_int = val.abs() >= 1.0;
has_int.write(stream)?;
let has_frac = val.fract() != 0.0;
has_frac.write(stream)?;
if has_frac || has_int {
let sign = val.is_negative();
sign.write(stream)?;
}
let abs = val.abs();
if has_int {
(abs as u16 - 1).write_sized(stream, 14)?;
}
if has_frac {
let frac_val = (abs.fract() / get_frac_factor(5)) as u8;
frac_val.write_sized(stream, 5)?;
}
Ok(())
}
#[test]
fn bit_coord_roundtrip() {
use bitbuffer::BitReadBuffer;
let mut write = BitWriteStream::new(LittleEndian);
write_bit_coord(0.0, &mut write).unwrap();
let pos1 = write.bit_len();
write_bit_coord(123.0, &mut write).unwrap();
let pos2 = write.bit_len();
write_bit_coord(123.4375, &mut write).unwrap();
let pos3 = write.bit_len();
write_bit_coord(-0.4375, &mut write).unwrap();
let pos4 = write.bit_len();
let mut read = Stream::from(BitReadBuffer::new_owned(write.finish(), LittleEndian));
assert_eq!(0.0, read_bit_coord(&mut read).unwrap());
assert_eq!(pos1, read.pos());
assert_eq!(123.0, read_bit_coord(&mut read).unwrap());
assert_eq!(pos2, read.pos());
assert_eq!(123.4375, read_bit_coord(&mut read).unwrap());
assert_eq!(pos3, read.pos());
assert_eq!(-0.4375, read_bit_coord(&mut read).unwrap());
assert_eq!(pos4, read.pos());
}
fn get_frac_factor(bits: usize) -> f32 { fn get_frac_factor(bits: usize) -> f32 {
1.0 / ((1 << bits) as f32) 1.0 / ((1 << bits) as f32)
} }

View file

@ -1,8 +1,8 @@
use bitbuffer::BitRead; use bitbuffer::{BitRead, BitWrite};
use parse_display::Display; use parse_display::Display;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
#[derive(BitRead, Debug, Clone, Copy, Default, Serialize, Deserialize, Display)] #[derive(BitRead, BitWrite, Debug, Clone, Copy, Default, Serialize, Deserialize, Display)]
#[display("({x}, {y}, {z})")] #[display("({x}, {y}, {z})")]
pub struct Vector { pub struct Vector {
pub x: f32, pub x: f32,
@ -16,7 +16,7 @@ impl PartialEq for Vector {
} }
} }
#[derive(BitRead, Debug, Clone, Copy, Default, Serialize, Deserialize, Display)] #[derive(BitRead, BitWrite, Debug, Clone, Copy, Default, Serialize, Deserialize, Display)]
#[display("({x}, {y})")] #[display("({x}, {y})")]
pub struct VectorXY { pub struct VectorXY {
pub x: f32, pub x: f32,

View file

@ -12,3 +12,24 @@ pub use crate::demo::{
pub(crate) mod consthash; pub(crate) mod consthash;
pub mod demo; pub mod demo;
mod nullhasher; mod nullhasher;
#[cfg(test)]
#[track_caller]
fn test_roundtrip_encode<
'a,
T: bitbuffer::BitRead<'a, bitbuffer::LittleEndian>
+ bitbuffer::BitWrite<bitbuffer::LittleEndian>
+ std::fmt::Debug
+ std::cmp::PartialEq,
>(
val: T,
) {
use bitbuffer::{BitReadBuffer, BitReadStream, BitWriteStream, LittleEndian};
let mut stream = BitWriteStream::new(LittleEndian);
val.write(&mut stream).unwrap();
let pos = stream.bit_len();
let mut read = BitReadStream::new(BitReadBuffer::new_owned(stream.finish(), LittleEndian));
assert_eq!(val, read.read().unwrap());
assert_eq!(pos, read.pos());
}