# read-fonts

This crate handles parsing and reading of OpenType fonts. It is intended to be a
high performance implementation suitable for tasks such as [shaping][], while
still providing a convenient, high-level API.

## Safety

Unsafe code is forbidden by a `#![forbid(unsafe_code)]` attribute in the root
of the library.

## codegen

Much of the code in this crate is generated automatically. This generated code
lives in the `generated` directory. Each file in this directory is included
in a module in the `src` directory, using Rust's [`include!`] macro. This allows
us to separate the generated code from any custom implementation code, while
allowing them to exist in the same module.

### what we generate

With certain exceptions that require manual handling, we generate code for each
*table*, *record*, *enum*, and *flags* type for each portion of the spec that we
cover.

## tables

All tables are newtype structs wrapping what is essentially a byte slice. When a
table is parsed, we perform _minimal validation_: that is, we ensure that the
provided data is at least long enough to contain all of the required,
non-version-dependent fields.

All other validation occurs at runtime. If table data is malformed, and a field
cannot be read, we will always return a default value. In the case of a
versioned field, this will always be `None`; for a field that is expected to
always be present, it will be the default value for the type in question,
usually either `0` or an empty array.

### variable length and version-dependent fields

**n.b**: *the design described below has not been benchmarked against the
alternatives, and may change*

For fields that have variable length, or which only exist in certain table
versions, the marker struct has a corresponding field where that length or
offset is stored. This means that at runtime there is no need to double check a
version or length.

## records

Unlike tables, which are essentially a set of methods for reading into a byte
slice, *records* are **in general** represented as simple packed structs
containing scalar types in big-endian encodings. This means that, in general,
records are zerocopy types that can be cast from raw bytes.

The exception to this is when a record has variable length; in this case the
record is still a simple struct, but cannot be cast from raw bytes, and must be
copied.

## flags and enums

For flags, we generate a type modeled on those generated by the [`bitflags!` macro][bitflags].
For enums, we generate a raw Rust enum.




[shaping]: https://fonts.google.com/knowledge/glossary/shaping
[`include!`]: http://doc.rust-lang.org/1.63.0/std/macro.include.html
[gdef-marker]: https://github.com/googlefonts/fontations/blob/main/read-fonts/generated/generated_gdef.rs#L11
[Gdef]: https://github.com/googlefonts/fontations/blob/main/read-fonts/generated/generated_gdef.rs#L77
[bitflags]: https://docs.rs/bitflags/latest/bitflags/
