From aaf68bc39d08be03ef59f8bd0b5a5bc7a5620a66 Mon Sep 17 00:00:00 2001 From: Picnoir Date: Thu, 21 Mar 2024 09:23:34 +0100 Subject: feat(tvix/nix-compat): add read_u32 wire primitive Change-Id: I87a40f79ee7e91bc4fe3dc0ee7818a533c729373 Reviewed-on: https://cl.tvl.fyi/c/depot/+/11225 Reviewed-by: flokli Tested-by: BuildkiteCI --- tvix/nix-compat/src/wire/primitive.rs | 36 ++++++++++++++++++++++++++++++++++- 1 file changed, 35 insertions(+), 1 deletion(-) diff --git a/tvix/nix-compat/src/wire/primitive.rs b/tvix/nix-compat/src/wire/primitive.rs index e675fcd2d1..a925bd00df 100644 --- a/tvix/nix-compat/src/wire/primitive.rs +++ b/tvix/nix-compat/src/wire/primitive.rs @@ -8,6 +8,27 @@ use tokio::io::{AsyncRead, AsyncReadExt, AsyncWrite, AsyncWriteExt}; pub static MAGIC_HELLO: [u8; 8] = *b"cxin\0\0\0\0"; // LE-encoded dxio on 64 bits. What's dxio? I have no clue. pub static MAGIC_HELLO_RESPONSE: [u8; 8] = *b"oixd\0\0\0\0"; +// LE-encoded protocol version. +pub static PROTOCOL_VERSION: [u8; 8] = [0x23, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]; + +/// Read a LE u32 from the least-significant bytes of a LE u64. +/// +/// Overall, it looks like this on the wire: +/// +/// 00 0x12 0x32 0x00 0x00 0x00 0x00 0x00 0x00 +/// |------------------|-------------------| +/// LE u32 padding +/// +/// Not sure why the protocol does this instead of using a plain u64, +/// but well, it is what it is. +/// +/// Analogous to the readInt function in cppnix. +pub async fn read_u32(r: &mut R) -> std::io::Result { + let val64 = r.read_u64_le().await?; + u32::try_from(val64).map_err(|_| { + std::io::Error::new(std::io::ErrorKind::InvalidData, "padding is not all zeroes") + }) +} #[allow(dead_code)] /// Read a u64 from the AsyncRead (little endian). @@ -35,7 +56,8 @@ pub async fn write_bool(w: &mut W, v: bool) -> std::io::R #[cfg(test)] mod tests { use super::*; - use tokio_test::io::Builder; + use hex_literal::hex; + use tokio_test::{assert_err, io::Builder}; // Integers. #[tokio::test] @@ -76,4 +98,16 @@ mod tests { let mut mock = Builder::new().write(&1u64.to_le_bytes()).build(); write_bool(&mut mock, true).await.unwrap(); } + #[tokio::test] + async fn test_read_u32() { + let mut mock = Builder::new().read(&hex!("7856341200000000")).build(); + let res = read_u32(&mut mock).await.unwrap(); + assert_eq!(res, 0x12345678); + } + #[tokio::test] + async fn test_read_too_large_u32_fail() { + let mut mock = Builder::new().read(&hex!("7856341298760000")).build(); + let res = read_u32(&mut mock).await; + assert_err!(res); + } } -- cgit 1.4.1