mirror of
https://github.com/typst/typst
synced 2025-05-20 12:05:27 +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 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;
|
use crate::layout::Ratio;
|
||||||
|
|
||||||
/// A floating-point number.
|
/// A floating-point number.
|
||||||
@ -106,6 +109,58 @@ impl f64 {
|
|||||||
pub fn signum(self) -> f64 {
|
pub fn signum(self) -> f64 {
|
||||||
f64::signum(self)
|
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 {
|
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)]
|
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash, Cast)]
|
||||||
pub enum Endianness {
|
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,
|
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,
|
Little,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -42,6 +42,17 @@
|
|||||||
#test(float(-calc.inf).signum(), -1.0)
|
#test(float(-calc.inf).signum(), -1.0)
|
||||||
#test(float(float.nan).signum().is-nan(), true)
|
#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 ---
|
--- float-repr ---
|
||||||
// Test the `repr` function with floats.
|
// Test the `repr` function with floats.
|
||||||
#repr(12.0) \
|
#repr(12.0) \
|
||||||
|
Loading…
x
Reference in New Issue
Block a user