xref: /aosp_15_r20/external/cronet/third_party/rust/chromium_crates_io/vendor/read-fonts-0.15.6/src/read.rs (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
1 //! Traits for interpreting font data
2 
3 use types::{BigEndian, FixedSize, Scalar, Tag};
4 
5 use crate::font_data::FontData;
6 
7 /// A type that can be read from raw table data.
8 ///
9 /// This trait is implemented for all font tables that are self-describing: that
10 /// is, tables that do not require any external state in order to interpret their
11 /// underlying bytes. (Tables that require external state implement
12 /// [`FontReadWithArgs`] instead)
13 pub trait FontRead<'a>: Sized {
14     /// Read an instace of `Self` from the provided data, performing validation.
15     ///
16     /// In the case of a table, this method is responsible for ensuring the input
17     /// data is consistent: this means ensuring that any versioned fields are
18     /// present as required by the version, and that any array lengths are not
19     /// out-of-bounds.
read(data: FontData<'a>) -> Result<Self, ReadError>20     fn read(data: FontData<'a>) -> Result<Self, ReadError>;
21 }
22 
23 //NOTE: this is separate so that it can be a super trait of FontReadWithArgs and
24 //ComputeSize, without them needing to know about each other? I'm not sure this
25 //is necessary, but I don't know the full heirarchy of traits I'm going to need
26 //yet, so this seems... okay?
27 
28 /// A trait for a type that needs additional arguments to be read.
29 pub trait ReadArgs {
30     type Args: Copy;
31 }
32 
33 /// A trait for types that require external data in order to be constructed.
34 ///
35 /// You should not need to use this directly; it is intended to be used from
36 /// generated code. Any type that requires external arguments also has a custom
37 /// `read` constructor where you can pass those arguments like normal.
38 pub trait FontReadWithArgs<'a>: Sized + ReadArgs {
39     /// read an item, using the provided args.
40     ///
41     /// If successful, returns a new item of this type, and the number of bytes
42     /// used to construct it.
43     ///
44     /// If a type requires multiple arguments, they will be passed as a tuple.
read_with_args(data: FontData<'a>, args: &Self::Args) -> Result<Self, ReadError>45     fn read_with_args(data: FontData<'a>, args: &Self::Args) -> Result<Self, ReadError>;
46 }
47 
48 // a blanket impl of ReadArgs/FontReadWithArgs for general FontRead types.
49 //
50 // This is used by ArrayOfOffsets/ArrayOfNullableOffsets to provide a common
51 // interface for regardless of whether a type has args.
52 impl<'a, T: FontRead<'a>> ReadArgs for T {
53     type Args = ();
54 }
55 
56 impl<'a, T: FontRead<'a>> FontReadWithArgs<'a> for T {
read_with_args(data: FontData<'a>, _: &Self::Args) -> Result<Self, ReadError>57     fn read_with_args(data: FontData<'a>, _: &Self::Args) -> Result<Self, ReadError> {
58         Self::read(data)
59     }
60 }
61 
62 /// A trait for tables that have multiple possible formats.
63 pub trait Format<T> {
64     /// The format value for this table.
65     const FORMAT: T;
66 }
67 
68 /// A type that can compute its size at runtime, based on some input.
69 ///
70 /// For types with a constant size, see [`FixedSize`] and
71 /// for types which store their size inline, see [`VarSize`].
72 pub trait ComputeSize: ReadArgs {
73     /// Compute the number of bytes required to represent this type.
compute_size(args: &Self::Args) -> usize74     fn compute_size(args: &Self::Args) -> usize;
75 }
76 
77 /// A trait for types that have variable length.
78 ///
79 /// As a rule, these types have an initial length field.
80 ///
81 /// For types with a constant size, see [`FixedSize`] and
82 /// for types which can pre-compute their size, see [`ComputeSize`].
83 pub trait VarSize {
84     /// The type of the first (length) field of the item.
85     ///
86     /// When reading this type, we will read this value first, and use it to
87     /// determine the total length.
88     type Size: Scalar + Into<u32>;
89 
90     #[doc(hidden)]
read_len_at(data: FontData, pos: usize) -> Option<usize>91     fn read_len_at(data: FontData, pos: usize) -> Option<usize> {
92         let asu32 = data.read_at::<Self::Size>(pos).ok()?.into();
93         Some(asu32 as usize + Self::Size::RAW_BYTE_LEN)
94     }
95 }
96 
97 /// A marker trait for types that can read from a big-endian buffer without copying.
98 ///
99 /// This is used as a trait bound on certain methods on [`FontData`] (such as
100 /// [`FontData::read_ref_at`] and [`FontData::read_array`]) in order to ensure
101 /// that those methods are only used with types that uphold certain safety
102 /// guarantees.
103 ///
104 /// WARNING: Do not implement this trait manually. Implementations are created
105 /// where appropriate during code generation, and there should be no conditions
106 /// under which this trait could be implemented, but cannot be implemented by
107 /// codegen.
108 ///
109 /// # Safety
110 ///
111 /// If a type `T` implements `FromBytes` then unsafe code may assume that it is
112 /// safe to interpret any sequence of bytes with length equal to
113 /// `std::mem::size_of::<T>()` as `T`.
114 ///
115 /// we additionally ensure the following conditions:
116 ///
117 /// - the type must have no internal padding
118 /// - `std::mem::align_of::<T>() == 1`
119 /// - for structs, the type is `repr(packed)` and `repr(C)`, and all fields are
120 ///   also `FromBytes`
121 ///
122 /// In practice, this trait is only implemented for `u8`, `BigEndian<T>`,
123 /// and for structs where all fields are those base types.
124 pub unsafe trait FromBytes: FixedSize + sealed::Sealed {
125     /// You should not be implementing this trait!
126     #[doc(hidden)]
this_trait_should_only_be_implemented_in_generated_code()127     fn this_trait_should_only_be_implemented_in_generated_code();
128 }
129 
130 // a sealed trait. see <https://rust-lang.github.io/api-guidelines/future-proofing.html>
131 pub(crate) mod sealed {
132     pub trait Sealed {}
133 }
134 
135 impl sealed::Sealed for u8 {}
136 // SAFETY: any byte can be interpreted as any other byte
137 unsafe impl FromBytes for u8 {
this_trait_should_only_be_implemented_in_generated_code()138     fn this_trait_should_only_be_implemented_in_generated_code() {}
139 }
140 
141 impl<T: Scalar> sealed::Sealed for BigEndian<T> {}
142 // SAFETY: BigEndian<T> is always wrapper around a transparent fixed-size byte array
143 unsafe impl<T: Scalar> FromBytes for BigEndian<T> {
this_trait_should_only_be_implemented_in_generated_code()144     fn this_trait_should_only_be_implemented_in_generated_code() {}
145 }
146 
147 /// An error that occurs when reading font data
148 #[derive(Debug, Clone)]
149 pub enum ReadError {
150     OutOfBounds,
151     // i64 is flexible enough to store any value we might encounter
152     InvalidFormat(i64),
153     InvalidSfnt(u32),
154     InvalidTtc(Tag),
155     InvalidCollectionIndex(u32),
156     InvalidArrayLen,
157     ValidationError,
158     NullOffset,
159     TableIsMissing(Tag),
160     MetricIsMissing(Tag),
161     MalformedData(&'static str),
162 }
163 
164 impl std::fmt::Display for ReadError {
fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result165     fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
166         match self {
167             ReadError::OutOfBounds => write!(f, "An offset was out of bounds"),
168             ReadError::InvalidFormat(x) => write!(f, "Invalid format '{x}'"),
169             ReadError::InvalidSfnt(ver) => write!(f, "Invalid sfnt version 0x{ver:08X}"),
170             ReadError::InvalidTtc(tag) => write!(f, "Invalid ttc tag {tag}"),
171             ReadError::InvalidCollectionIndex(ix) => {
172                 write!(f, "Invalid index {ix} for font collection")
173             }
174             ReadError::InvalidArrayLen => {
175                 write!(f, "Specified array length not a multiple of item size")
176             }
177             ReadError::ValidationError => write!(f, "A validation error occured"),
178             ReadError::NullOffset => write!(f, "An offset was unexpectedly null"),
179             ReadError::TableIsMissing(tag) => write!(f, "the {tag} table is missing"),
180             ReadError::MetricIsMissing(tag) => write!(f, "the {tag} metric is missing"),
181             ReadError::MalformedData(msg) => write!(f, "Malformed data: '{msg}'"),
182         }
183     }
184 }
185 
186 #[cfg(feature = "std")]
187 impl std::error::Error for ReadError {}
188