Bound Trait Syntax Help

New to Rust. Inherited some code that I don't understand:

use nalgebra::DimName;
pub struct Parameters<D>
where
    D: DimName,
    <D as DimName>::Value: Mul + Mul<UInt>,
    <<D as DimName>::Value as Mul<UInt>>::Output: ArrayLength<f64>,

...

I understand that D has to be a DimName, but other than that, I'm pretty lost. Can someone help?

(Also, if someone can explain an nalgebra::DimName, that would be great -- the docs aren't super transparent.)

Thanks,

D has to be a type-level integer, either from nalgebra itself (in nalgebra::base::dimension) (for small numbers) or from the typenum crate (for larger numbers).

DimName is just a trait that nalgebra uses for type-level integers used as array sizes. I don't know why it's called DimName; the purpose might have been that it is used in error messages to give user-friendly sizes or something. Maybe. It seems mostly the purpose however is to abstract over nalgebra's type ints and typenum's type ints.

Confusingly, there's also a trait called NamedDim that it seems users aren't supposed to use; I honestly couldn't tell you the difference without careful inspection of the impls. Unfortunately, as a crate with heavy amounts of type-level programming, nalgebra often has an issue with an excess of traits that seem redundant to the user (but are required for technical reasons).

Thanks.

Can you explain the syntax of the "where" clause?

A where clause is a comma-separated list of bounds on types.

A bound on a type has the form TYPE: BOUNDS, where BOUNDS is a +-separated list of traits that are satisfied by the type. Traits and types have basically the same grammar, so that leaves just types to explain.

Obviously, an identifier or something like Name<A, B>
(or more generally some::path::Name<A, B>) are types. A bit less obvious is that <D as DimName>::Value is also a type. This is what we call an associated type projection. (the compiler also calls these QPaths, for "qualified path"). It looks up the associated type Value defined in the impl of the trait DimName for the type D. Hence, the second bound is saying that the Value type for D must implement the traits Mul and Mul<UInt>.