summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author+merlan #flirora <uruwi@protonmail.com>2024-11-27 06:04:54 -0500
committerGitHub <noreply@github.com>2024-11-27 11:04:54 +0000
commit6bf1350b16b90ae915836f94dff440da671ebd45 (patch)
treecac250782e46775a7751b28d495e1f3065fad994
parente550dce62d3def1fb2dfbd1f2b15491e1424da09 (diff)
Add support for interpreting f32 in float.{from-bytes, to-bytes} (#5480)
-rw-r--r--crates/typst-library/src/foundations/float.rs47
-rw-r--r--tests/suite/foundations/float.typ7
2 files changed, 38 insertions, 16 deletions
diff --git a/crates/typst-library/src/foundations/float.rs b/crates/typst-library/src/foundations/float.rs
index bb3232ee..c3d4e0e7 100644
--- a/crates/typst-library/src/foundations/float.rs
+++ b/crates/typst-library/src/foundations/float.rs
@@ -128,16 +128,21 @@ impl f64 {
#[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"),
+ // Convert slice to an array of length 4 or 8.
+ if let Ok(buffer) = <[u8; 8]>::try_from(bytes.as_ref()) {
+ return Ok(match endian {
+ Endianness::Little => f64::from_le_bytes(buffer),
+ Endianness::Big => f64::from_be_bytes(buffer),
+ });
+ };
+ if let Ok(buffer) = <[u8; 4]>::try_from(bytes.as_ref()) {
+ return Ok(match endian {
+ Endianness::Little => f32::from_le_bytes(buffer),
+ Endianness::Big => f32::from_be_bytes(buffer),
+ } as f64);
};
- Ok(match endian {
- Endianness::Little => f64::from_le_bytes(buf),
- Endianness::Big => f64::from_be_bytes(buf),
- })
+ bail!("bytes must have a length of 4 or 8");
}
/// Converts a float to bytes.
@@ -153,13 +158,25 @@ impl f64 {
#[named]
#[default(Endianness::Little)]
endian: Endianness,
- ) -> Bytes {
- match endian {
- Endianness::Little => self.to_le_bytes(),
- Endianness::Big => self.to_be_bytes(),
- }
- .as_slice()
- .into()
+ #[named]
+ #[default(8)]
+ size: u32,
+ ) -> StrResult<Bytes> {
+ Ok(match size {
+ 8 => match endian {
+ Endianness::Little => self.to_le_bytes(),
+ Endianness::Big => self.to_be_bytes(),
+ }
+ .as_slice()
+ .into(),
+ 4 => match endian {
+ Endianness::Little => (self as f32).to_le_bytes(),
+ Endianness::Big => (self as f32).to_be_bytes(),
+ }
+ .as_slice()
+ .into(),
+ _ => bail!("size must be either 4 or 8"),
+ })
}
}
diff --git a/tests/suite/foundations/float.typ b/tests/suite/foundations/float.typ
index 2e9e07f2..716ecd6b 100644
--- a/tests/suite/foundations/float.typ
+++ b/tests/suite/foundations/float.typ
@@ -53,8 +53,13 @@
#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)))
+#test(float.from-bytes(bytes((0, 0, 32, 64))), 2.5)
+#test(float.from-bytes(bytes((64, 32, 0, 0)), endian: "big"), 2.5)
+#test(2.5.to-bytes(size: 4), bytes((0, 0, 32, 64)))
+#test(2.5.to-bytes(size: 4, endian: "big"), bytes((64, 32, 0, 0)))
+
--- float-from-bytes-bad-length ---
-// Error: 2-54 bytes must have a length of exactly 8
+// Error: 2-54 bytes must have a length of 4 or 8
#float.from-bytes(bytes((0, 0, 0, 0, 0, 0, 0, 1, 0)))
--- float-repr ---