Closes gaps found by an external source-level audit of a downstream consumer (retroglyph), which
hand-rolled all of these repeatedly. All changes are additive.
### Added
- `Rect::clamp_within()` — moves (not shrinks) a rectangle so it fits inside a bounding rectangle,
keeping its size; the "keep this popup/viewport on screen" operation
- `Rect::centered_in()` — centers a rectangle's size within a bounding rectangle, then
`clamp_within`s it
- `Rect::inset()` / `Rect::outset()` — asymmetric, saturating grow/shrink by a `top`/`right`/
`bottom`/`left` amount per edge, unlike the symmetric, panic-on-underflow `inflate`/`shrink`
- `Size<T>` parity with `Pos<T>`: `Default`, `From<(T, T)>`/`From<[T; 2]>` (and the reverse
conversions), and `PartialOrd`/`Ord` (width-primary, then height)
- `Rect<T>: Mul<Size<T>>`/`MulAssign<Size<T>>` — per-axis scaling (e.g. cell→pixel with
non-square cells), complementing the existing uniform `Mul<T>`
- `Int::saturating_add()`/`Int::saturating_sub()` — generic saturating arithmetic, backing the
saturating `Rect` methods above
### Fixed
- `Rect::row_rect()`/`Rect::col_rect()` didn't clamp `row`/`col`, contradicting their own doc
claim that the result is "guaranteed to be within the bounds of this rectangle": an
out-of-bounds index (e.g. `rect.row_rect(100)` on a 4-row rectangle) produced a rectangle
entirely outside the source rectangle instead of clamping to the last valid row/column.