From 5823429a968eeb60f39aba55302f4fca57bdf615 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim=20Vo=C3=9Fhenrich?= <94936637+T1mVo@users.noreply.github.com> Date: Thu, 26 Sep 2024 11:14:45 +0200 Subject: Add float to bytes conversion and vice-versa (#4989) Co-authored-by: Laurenz --- crates/typst/src/foundations/float.rs | 57 ++++++++++++++++++++++++++++++++++- crates/typst/src/foundations/int.rs | 9 ++++-- 2 files changed, 62 insertions(+), 4 deletions(-) (limited to 'crates') diff --git a/crates/typst/src/foundations/float.rs b/crates/typst/src/foundations/float.rs index fd094950..ff3e62a5 100644 --- a/crates/typst/src/foundations/float.rs +++ b/crates/typst/src/foundations/float.rs @@ -2,7 +2,10 @@ use std::num::ParseFloatError; use ecow::{eco_format, EcoString}; -use crate::foundations::{cast, func, repr, scope, ty, Repr, Str}; +use crate::diag::StrResult; +use crate::foundations::{ + bail, cast, func, repr, scope, ty, Bytes, Endianness, Repr, Str, +}; use crate::layout::Ratio; /// A floating-point number. @@ -106,6 +109,58 @@ impl f64 { pub fn signum(self) -> f64 { f64::signum(self) } + + /// Converts bytes to a float. + /// + /// ```example + /// #float.from-bytes(bytes((0, 0, 0, 0, 0, 0, 240, 63))) \ + /// #float.from-bytes(bytes((63, 240, 0, 0, 0, 0, 0, 0)), endian: "big") + /// ``` + #[func] + pub fn from_bytes( + /// The bytes that should be converted to a float. + /// + /// Must be of length exactly 8 so that the result fits into a 64-bit + /// float. + bytes: Bytes, + /// The endianness of the conversion. + #[named] + #[default(Endianness::Little)] + endian: Endianness, + ) -> StrResult { + // Convert slice to an array of length 8. + let buf: [u8; 8] = match bytes.as_ref().try_into() { + Ok(buffer) => buffer, + Err(_) => bail!("bytes must have a length of exactly 8"), + }; + + Ok(match endian { + Endianness::Little => f64::from_le_bytes(buf), + Endianness::Big => f64::from_be_bytes(buf), + }) + } + + /// Converts a float to bytes. + /// + /// ```example + /// #array(1.0.to-bytes(endian: "big")) \ + /// #array(1.0.to-bytes()) + /// ``` + #[func] + pub fn to_bytes( + self, + /// The endianness of the conversion. + #[named] + #[default(Endianness::Little)] + endian: Endianness, + ) -> Bytes { + match endian { + Endianness::Little => self.to_le_bytes(), + Endianness::Big => self.to_be_bytes(), + } + .as_slice() + .into() + } } impl Repr for f64 { diff --git a/crates/typst/src/foundations/int.rs b/crates/typst/src/foundations/int.rs index 4c1335fc..79a8a86f 100644 --- a/crates/typst/src/foundations/int.rs +++ b/crates/typst/src/foundations/int.rs @@ -341,12 +341,15 @@ impl Repr for i64 { } } -/// Represents the byte order used for converting integers to bytes and vice versa. +/// Represents the byte order used for converting integers and floats to bytes +/// and vice versa. #[derive(Debug, Copy, Clone, Eq, PartialEq, Hash, Cast)] pub enum Endianness { - /// Big-endian byte order: the highest-value byte is at the beginning of the bytes. + /// Big-endian byte order: The highest-value byte is at the beginning of the + /// bytes. Big, - /// Little-endian byte order: the lowest-value byte is at the beginning of the bytes. + /// Little-endian byte order: The lowest-value byte is at the beginning of + /// the bytes. Little, } -- cgit v1.2.3