1# Architecture
2
3This document describes the high-level architecture of `glam`. While `glam` is
4not a large library there are some complexities to its implementation. The
5rational and explanation of these follows.
6
7## Design goals
8
9There overarching design goals of glam are:
10
11* Good out of the box performance using SIMD when available
12* Has a simple public interface
13* Is fast to compile
14* Follow Rust [standard library] conventions and [API guidelines] where possible
15* High quality [rustdoc] generated document
16
17[standard library]: https://doc.rust-lang.org/std/index.html
18[API guidelines]: https://rust-lang.github.io/api-guidelines
19[rustdoc]: https://doc.rust-lang.org/rustdoc/index.html
20
21### SIMD
22
23One of the core premises of `glam` was that using SSE2 instructions on `x86` and
24`x86_64` architectures gave better performance than using Rust's built in `f32`
25type. For more on this finding see [Optimising path tracing with SIMD].
26
27I also wanted to have a `f32` fallback when SIMD was not available.
28
29[Optimising path tracing with SIMD]: https://bitshifter.github.io/2018/06/04/simd-path-tracing/#converting-vec3-to-sse2.
30
31### No generics
32
33Because internally storage could be a SIMD vector intrinsic like `__m128` on
34`x86` or say an array of `f32` if SSE2 was not available, a simple generic
35parameter like `Vec4<T>` could not be used. The `T` would specify the public
36facing type, but not storage. Perhaps this could be achieved with a second
37generic parameter for storage, e.g. `Vec4<f32, __m128>` or `Vec4<f32, [f32; 4]>`
38but I felt that such a design would introduce a lot of complexity that end users
39would ultimately be burdened with, so it's not something that was pursued.
40
41Generics can also increase compile time and code size which is something glam
42wants to avoid.
43
44### No traits
45
46`glam` also mostly avoids using traits in the public interface. Primarily
47because there wasn't a good reason to. A `Vec3` is not an interface, it is a
48concrete type. The secondary reason is traits fragment documentation. If the
49functionality of a `Vec3` is implemented across a number of different traits
50then the documentation of all of the `Vec3` methods will be on the individual
51traits, not the `Vec3` itself. This makes it harder for users to find what
52methods a struct actually implements as the documentation is not in one place.
53
54Conversely `glam` does use traits for swizzle methods so that the documentation
55for these methods is on the trait and not the `Vec2`, `Vec3`, `Vec4` and so on
56structs. There are many swizzle methods which would clutter the documentation,
57making them a trait means they won't pollute documentation.
58
59### Support common primitives
60
61Initially `glam` only supported `f32` which kept the internal implementation
62relatively simple. However users also wanted support for other primitives types
63like `f64`, `i32` and `u32`. Because `glam` avoids using `generics` adding
64support for other primitive types without a lot of code duplication required
65some additional complexity in implementation.
66
67## High level structure
68
69`glam` supports a number of permutations of vector, quaternion and matrix types
70for `f32`, `f64`, `i32` and `u32` primitives, with SSE2 or wasm32 for some `f32`
71types and scalar fallbacks if SIMD is not available.
72
73### Component access via Deref
74
75The `Deref` trait is used to provide direct access to SIMD vector components
76like `.x`, `.y` and so on.  The `Deref` implementation will return `XYZ<T>`
77structure on which the vector components are accessible. Unfortunately if users
78dereference the public types they will see confusing errors messages about
79`XYZ` types but this on balance seemed preferable to needing to setter and
80getting methods to read and write component values.
81
82## Code generation
83
84See the [codegen README] for information on `glam`'s code generation process.
85
86[codegen README]: codegen/README.md
87