summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTim Voßhenrich <94936637+T1mVo@users.noreply.github.com>2024-09-26 11:14:45 +0200
committerGitHub <noreply@github.com>2024-09-26 09:14:45 +0000
commit5823429a968eeb60f39aba55302f4fca57bdf615 (patch)
tree7444e64055844d083275c5bb2de33c6d053452cb
parent4827f28a940b9610e55afb888ddde11e240caa20 (diff)
Add float to bytes conversion and vice-versa (#4989)
Co-authored-by: Laurenz <laurmaedje@gmail.com>
-rw-r--r--crates/typst/src/foundations/float.rs57
-rw-r--r--crates/typst/src/foundations/int.rs9
-rw-r--r--tests/suite/foundations/float.typ11
3 files changed, 73 insertions, 4 deletions
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<f64> {
+ // 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,
}
diff --git a/tests/suite/foundations/float.typ b/tests/suite/foundations/float.typ
index 01769260..67d4acbf 100644
--- a/tests/suite/foundations/float.typ
+++ b/tests/suite/foundations/float.typ
@@ -42,6 +42,17 @@
#test(float(-calc.inf).signum(), -1.0)
#test(float(float.nan).signum().is-nan(), true)
+--- float-from-and-to-bytes ---
+// Test float `from-bytes()` and `to-bytes()`.
+#test(float.from-bytes(bytes((0, 0, 0, 0, 0, 0, 240, 63))), 1.0)
+#test(float.from-bytes(bytes((63, 240, 0, 0, 0, 0, 0, 0)), endian: "big"), 1.0)
+#test(1.0.to-bytes(), bytes((0, 0, 0, 0, 0, 0, 240, 63)))
+#test(1.0.to-bytes(endian: "big"), bytes((63, 240, 0, 0, 0, 0, 0, 0)))
+
+--- float-from-bytes-bad-length ---
+// Error: 2-54 bytes must have a length of exactly 8
+#float.from-bytes(bytes((0, 0, 0, 0, 0, 0, 0, 1, 0)))
+
--- float-repr ---
// Test the `repr` function with floats.
#repr(12.0) \