mirror of
https://github.com/typst/typst
synced 2025-05-20 03:55:29 +08:00
Add float to bytes conversion and vice-versa (#4989)
Co-authored-by: Laurenz <laurmaedje@gmail.com>
This commit is contained in:
parent
4827f28a94
commit
5823429a96
@ -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 {
|
||||
|
@ -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,
|
||||
}
|
||||
|
||||
|
@ -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) \
|
||||
|
Loading…
x
Reference in New Issue
Block a user