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