about summary refs log tree commit diff
path: root/tvix/nix-compat/src/wire/de/int.rs
diff options
context:
space:
mode:
authorVova Kryachko <v.kryachko@gmail.com>2024-11-10T16·16-0500
committerVladimir Kryachko <v.kryachko@gmail.com>2024-11-10T20·54+0000
commit8df919dcf04b5c2502f3a63b4d013669da5e70c1 (patch)
tree3a527553fc48f62f331ef2b6a5667b6fe591290d /tvix/nix-compat/src/wire/de/int.rs
parent11ee751aff42804319788a9033685a455bdf8f8e (diff)
refactor(nix-compat): Move serialization machinery into wire. r/8898
This groups most `wire` feature gated logic into a single module.
The nix_daemon module will be gated by a feature that adds
nix-compat-derive as a dependency.

All of this is a way to break the crate2nix dependency cycle between
nix-compat and nix-compat-derive(which depends on nix-compat for its
doctests).

Change-Id: I95938a6f280c11967371ff21f8b5a19e6d3d3805
Reviewed-on: https://cl.tvl.fyi/c/depot/+/12761
Tested-by: BuildkiteCI
Reviewed-by: flokli <flokli@flokli.de>
Diffstat (limited to 'tvix/nix-compat/src/wire/de/int.rs')
-rw-r--r--tvix/nix-compat/src/wire/de/int.rs100
1 files changed, 100 insertions, 0 deletions
diff --git a/tvix/nix-compat/src/wire/de/int.rs b/tvix/nix-compat/src/wire/de/int.rs
new file mode 100644
index 000000000000..d505de9b1b24
--- /dev/null
+++ b/tvix/nix-compat/src/wire/de/int.rs
@@ -0,0 +1,100 @@
+use super::{Error, NixDeserialize, NixRead};
+
+impl NixDeserialize for u64 {
+    async fn try_deserialize<R>(reader: &mut R) -> Result<Option<Self>, R::Error>
+    where
+        R: ?Sized + NixRead + Send,
+    {
+        reader.try_read_number().await
+    }
+}
+
+impl NixDeserialize for usize {
+    async fn try_deserialize<R>(reader: &mut R) -> Result<Option<Self>, R::Error>
+    where
+        R: ?Sized + NixRead + Send,
+    {
+        if let Some(value) = reader.try_read_number().await? {
+            value.try_into().map_err(R::Error::invalid_data).map(Some)
+        } else {
+            Ok(None)
+        }
+    }
+}
+
+impl NixDeserialize for bool {
+    async fn try_deserialize<R>(reader: &mut R) -> Result<Option<Self>, R::Error>
+    where
+        R: ?Sized + NixRead + Send,
+    {
+        Ok(reader.try_read_number().await?.map(|v| v != 0))
+    }
+}
+impl NixDeserialize for i64 {
+    async fn try_deserialize<R>(reader: &mut R) -> Result<Option<Self>, R::Error>
+    where
+        R: ?Sized + NixRead + Send,
+    {
+        Ok(reader.try_read_number().await?.map(|v| v as i64))
+    }
+}
+
+#[cfg(test)]
+mod test {
+    use hex_literal::hex;
+    use rstest::rstest;
+    use tokio_test::io::Builder;
+
+    use crate::wire::de::{NixRead, NixReader};
+
+    #[rstest]
+    #[case::simple_false(false, &hex!("0000 0000 0000 0000"))]
+    #[case::simple_true(true, &hex!("0100 0000 0000 0000"))]
+    #[case::other_true(true, &hex!("1234 5600 0000 0000"))]
+    #[case::max_true(true, &hex!("FFFF FFFF FFFF FFFF"))]
+    #[tokio::test]
+    async fn test_read_bool(#[case] expected: bool, #[case] data: &[u8]) {
+        let mock = Builder::new().read(data).build();
+        let mut reader = NixReader::new(mock);
+        let actual: bool = reader.read_value().await.unwrap();
+        assert_eq!(actual, expected);
+    }
+
+    #[rstest]
+    #[case::zero(0, &hex!("0000 0000 0000 0000"))]
+    #[case::one(1, &hex!("0100 0000 0000 0000"))]
+    #[case::other(0x563412, &hex!("1234 5600 0000 0000"))]
+    #[case::max_value(u64::MAX, &hex!("FFFF FFFF FFFF FFFF"))]
+    #[tokio::test]
+    async fn test_read_u64(#[case] expected: u64, #[case] data: &[u8]) {
+        let mock = Builder::new().read(data).build();
+        let mut reader = NixReader::new(mock);
+        let actual: u64 = reader.read_value().await.unwrap();
+        assert_eq!(actual, expected);
+    }
+
+    #[rstest]
+    #[case::zero(0, &hex!("0000 0000 0000 0000"))]
+    #[case::one(1, &hex!("0100 0000 0000 0000"))]
+    #[case::other(0x563412, &hex!("1234 5600 0000 0000"))]
+    #[case::max_value(usize::MAX, &usize::MAX.to_le_bytes())]
+    #[tokio::test]
+    async fn test_read_usize(#[case] expected: usize, #[case] data: &[u8]) {
+        let mock = Builder::new().read(data).build();
+        let mut reader = NixReader::new(mock);
+        let actual: usize = reader.read_value().await.unwrap();
+        assert_eq!(actual, expected);
+    }
+
+    // FUTUREWORK: Test this on supported hardware
+    #[tokio::test]
+    #[cfg(any(target_pointer_width = "16", target_pointer_width = "32"))]
+    async fn test_read_usize_overflow() {
+        let mock = Builder::new().read(&u64::MAX.to_le_bytes()).build();
+        let mut reader = NixReader::new(mock);
+        assert_eq!(
+            std::io::ErrorKind::InvalidData,
+            reader.read_value::<usize>().await.unwrap_err().kind()
+        );
+    }
+}