# 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 aliases of the type `TableRef<Marker>`, where `Marker` is a
struct that indicates the type of the table. For instance, the [GDEF table][Gdef]
is defined as `TableRef<GdefMarker>`. `TableRef` itself is a wrapper around a
slice of bytes, with the *marker* type providing typed access to those bytes.

The marker type can only be created from a specific byte slice, and is always
associated with that slice. It is created through a `parse` method that performs
a one-time validation of the slice, ensuring that all expected fields are
present. This includes bounds checking any arrays, as well as ensuring the
presence of fields the existence of which may depend on the table's version.

### variable lengths 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.

### TableRef methods

For each table, we define methods on the type `TableRef<Marker>` that provide
access to that table's fields. These methods use the marker type to determine
the byte range of a given field, and then interpret those bytes as the
appropriate type.

## 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/
