summaryrefslogtreecommitdiff
path: root/crates/typst-library/src/foundations/bytes.rs
diff options
context:
space:
mode:
authorLaurenz <laurmaedje@gmail.com>2025-01-09 10:34:16 +0100
committerGitHub <noreply@github.com>2025-01-09 09:34:16 +0000
commite2b37fef33a92a7086790e04fb133472413c0c0a (patch)
treea2bdc638482890183414dce18f8f586786154017 /crates/typst-library/src/foundations/bytes.rs
parentdacd6acd5e73d35c6e7a7a3b144f16ae70d03daa (diff)
Revamp data loading and deprecate `decode` functions (#5671)
Diffstat (limited to 'crates/typst-library/src/foundations/bytes.rs')
-rw-r--r--crates/typst-library/src/foundations/bytes.rs51
1 files changed, 48 insertions, 3 deletions
diff --git a/crates/typst-library/src/foundations/bytes.rs b/crates/typst-library/src/foundations/bytes.rs
index 20034d07..d633c99a 100644
--- a/crates/typst-library/src/foundations/bytes.rs
+++ b/crates/typst-library/src/foundations/bytes.rs
@@ -2,6 +2,7 @@ use std::any::Any;
use std::fmt::{self, Debug, Formatter};
use std::hash::{Hash, Hasher};
use std::ops::{Add, AddAssign, Deref};
+use std::str::Utf8Error;
use std::sync::Arc;
use ecow::{eco_format, EcoString};
@@ -80,16 +81,37 @@ impl Bytes {
self.as_slice().is_empty()
}
- /// Return a view into the buffer.
+ /// Return a view into the bytes.
pub fn as_slice(&self) -> &[u8] {
self
}
- /// Return a copy of the buffer as a vector.
+ /// Try to view the bytes as an UTF-8 string.
+ ///
+ /// If these bytes were created via `Bytes::from_string`, UTF-8 validation
+ /// is skipped.
+ pub fn as_str(&self) -> Result<&str, Utf8Error> {
+ self.inner().as_str()
+ }
+
+ /// Return a copy of the bytes as a vector.
pub fn to_vec(&self) -> Vec<u8> {
self.as_slice().to_vec()
}
+ /// Try to turn the bytes into a `Str`.
+ ///
+ /// - If these bytes were created via `Bytes::from_string::<Str>`, the
+ /// string is cloned directly.
+ /// - If these bytes were created via `Bytes::from_string`, but from a
+ /// different type of string, UTF-8 validation is still skipped.
+ pub fn to_str(&self) -> Result<Str, Utf8Error> {
+ match self.inner().as_any().downcast_ref::<Str>() {
+ Some(string) => Ok(string.clone()),
+ None => self.as_str().map(Into::into),
+ }
+ }
+
/// Resolve an index or throw an out of bounds error.
fn locate(&self, index: i64) -> StrResult<usize> {
self.locate_opt(index).ok_or_else(|| out_of_bounds(index, self.len()))
@@ -104,6 +126,11 @@ impl Bytes {
if index >= 0 { Some(index) } else { (len as i64).checked_add(index) };
wrapped.and_then(|v| usize::try_from(v).ok()).filter(|&v| v <= len)
}
+
+ /// Access the inner `dyn Bytelike`.
+ fn inner(&self) -> &dyn Bytelike {
+ &**self.0
+ }
}
#[scope]
@@ -203,7 +230,7 @@ impl Deref for Bytes {
type Target = [u8];
fn deref(&self) -> &Self::Target {
- self.0.as_bytes()
+ self.inner().as_bytes()
}
}
@@ -262,6 +289,8 @@ impl Serialize for Bytes {
/// Any type that can back a byte buffer.
trait Bytelike: Send + Sync {
fn as_bytes(&self) -> &[u8];
+ fn as_str(&self) -> Result<&str, Utf8Error>;
+ fn as_any(&self) -> &dyn Any;
fn as_any_mut(&mut self) -> &mut dyn Any;
}
@@ -273,6 +302,14 @@ where
self.as_ref()
}
+ fn as_str(&self) -> Result<&str, Utf8Error> {
+ std::str::from_utf8(self.as_ref())
+ }
+
+ fn as_any(&self) -> &dyn Any {
+ self
+ }
+
fn as_any_mut(&mut self) -> &mut dyn Any {
self
}
@@ -295,6 +332,14 @@ where
self.0.as_ref().as_bytes()
}
+ fn as_str(&self) -> Result<&str, Utf8Error> {
+ Ok(self.0.as_ref())
+ }
+
+ fn as_any(&self) -> &dyn Any {
+ self
+ }
+
fn as_any_mut(&mut self) -> &mut dyn Any {
self
}