# Rust rules

Apply these rules to every relevant file in this project.

- Do not assume this is safe: code keeps a reference to a `Vec` element and then calls `push`, assuming an unrelated tail element is all that changes.
  Why: Growth can move the entire buffer, so the borrow checker rejects the mutation when the old reference will be used again.
  Source: [Borrowing rules](https://codewiki.com/rust/borrowing-rules/)
- Generated code often adds `.clone()` beside every borrow error.
  Why: This can make the code compile, but it silently turns shared observation into allocation and copying and hides whether the function should borrow or take ownership.
  Source: [Borrowing rules](https://codewiki.com/rust/borrowing-rules/)
- A lifetime annotation cannot make a local value live longer.
  Why: Adding `'static` to the result or `'a` to both input and output cannot turn a reference to a soon-to-be-destroyed local `String` into a valid result.
  Source: [Borrowing rules](https://codewiki.com/rust/borrowing-rules/)
- Do not assume this is safe: `&mut T` is not `Copy`.
  Why: After assigning a mutable reference directly to another variable, using the old variable can produce “use of moved value”; this follows from the same permission model that prevents arbitrary duplicate exclusive access.
  Source: [Borrowing rules](https://codewiki.com/rust/borrowing-rules/)
- Adding blocks everywhere to “shorten the lifetime” can make code pass while concealing an overly broad interface or unsuitable data layout.
  Why: NLL already ends many borrows at their last use, so another scope is not the default answer.
  Source: [Borrowing rules](https://codewiki.com/rust/borrowing-rules/)
- Do not assume this is safe: mechanically replacing a failing `Rc>` with `Arc>` does not make `RefCell` implement `Sync`.
  Why: Nor does `Arc` automatically provide a way to mutate `T`.
  Source: [Box, Rc and Arc](https://codewiki.com/rust/box-rc-arc/)
- Generated trees, observer lists, and graphs often store `Rc` or `Arc` in both directions.
  Why: After all external handles are dropped, every strong count in the cycle remains above zero, so destructors never run.
  Source: [Box, Rc and Arc](https://codewiki.com/rust/box-rc-arc/)
- `weak.upgrade().unwrap()` turns “the target may have ended” into a false invariant.
  Why: In event queues, async callbacks, and cross-thread registries, the last strong owner can disappear before the weak handle is used.
  Source: [Box, Rc and Arc](https://codewiki.com/rust/box-rc-arc/)
- Generated code around `Arc>>` often invokes each callback while holding the mutex.
  Why: A callback that re-enters the registry can deadlock, and a slow callback blocks every subscribe and publish operation.
  Source: [Box, Rc and Arc](https://codewiki.com/rust/box-rc-arc/)
- Do not assume this is safe: `Box` supplies owning indirection, but an ordinary `Box` does not express the fixed-address guarantee required by a self-referential value, nor does it guarantee faster code.
  Why: Boxing every small value adds indirection and may introduce heap allocation.
  Source: [Box, Rc and Arc](https://codewiki.com/rust/box-rc-arc/)
- Do not assume this is safe: `Cell::get()` requires `T: Copy`, but the `Cell` type itself does not.
  Why: Generated code often changes `Cell` into `RefCell` for this reason, adding dynamic borrow state and panic paths for no benefit.
  Source: [Cell and RefCell](https://codewiki.com/rust/refcell-cell/)
- A guard obtained by iterating over `self.callbacks.borrow()` usually spans the whole loop.
  Why: Any callback that registers or removes a callback, or calls another method borrowing the same cell, can trigger a runtime panic.
  Source: [Cell and RefCell](https://codewiki.com/rust/refcell-cell/)
- Do not assume this is safe: an error from `try_borrow_mut()` does not mean another thread temporarily holds a lock.
  Why: `RefCell` cannot be shared across threads; the error means the current call stack, an iterator, or a returned guard still holds conflicting access.
  Source: [Cell and RefCell](https://codewiki.com/rust/refcell-cell/)
- Wrapping a value in `Rc>` to get past one compile-time borrow error adds shared ownership, runtime panics, and possible strong-reference cycles at once.
  Why: The original state owner also becomes harder to identify.
  Source: [Cell and RefCell](https://codewiki.com/rust/refcell-cell/)
- Do not assume this is safe: changing local state into `Rc>` and later capturing the handle in a thread or multithreaded async task fails when the task requires `Send`.
  Why: More calls to `clone()` cannot add `Send` or `Sync`, and they provide no synchronization.
  Source: [Cell and RefCell](https://codewiki.com/rust/refcell-cell/)
- Returning a guard can avoid a copy, but exposes internal dynamic borrow state to the caller.
  Why: If the caller retains it in a wide scope, a later and apparently unrelated `&self` method may panic.
  Source: [Cell and RefCell](https://codewiki.com/rust/refcell-cell/)
- You equate `move` with one call.
  Why: `move` controls how the closure obtains its environment. The closure loses `FnMut` and `Fn` only when its body moves data out of a capture. Fix: Answer two separate questions: how a value enters the closure, and how a call uses it. A closure that only reads a by-value `String` may still implement `Fn`; do not clone repeatedly to satisfy a false assumption.
  Source: [Closures](https://codewiki.com/rust/closures/)
- A callback has an unnecessarily strong trait bound.
  Why: Requiring `Fn` for a one-shot function rejects consuming closures; requiring it for a retry helper rejects a natural mutable counter. Fix: Derive the bound from the implementation's call count. Choose `FnOnce` for one call, `FnMut` for repetition with possible state changes, and `Fn` only when a shared receiver is required.
  Source: [Closures](https://codewiki.com/rust/closures/)
- You expect `move` to repair every lifetime error.
  Why: If the captured variable is itself a reference, `move` transfers only that reference. The underlying data may still die too soon for a return value or thread. Fix: Create genuinely owned data at the ownership boundary, or keep the correct borrowing lifetime on the return type. Do not add `'static` mechanically or clone an entire context before checking the cost.
  Source: [Closures](https://codewiki.com/rust/closures/)
- You put different closures straight into one collection.
  Why: Each closure expression has its own type; matching signatures do not make them the same element type. Fix: Non-capturing closures can share a `fn` pointer type, open heterogeneous collections can use `Box`, and a closed set can use an enum. The representation should match the runtime model.
  Source: [Closures](https://codewiki.com/rust/closures/)
- You omit thread and lifetime bounds from a trait object.
  Why: `Box` does not automatically include `Send`, `Sync`, or the right object lifetime, so a cross-thread registry may fail far from the storage boundary. Fix: State real requirements such as `Box` at the callback API boundary and inspect every capture. Do not add concurrency bounds when one thread owns all calls.
  Source: [Closures](https://codewiki.com/rust/closures/)
- A broad clone hides a capture conflict.
  Why: Generated code often clones a whole request context or collection into a closure just to remove one borrow error. That obscures ownership and adds allocation. Fix: Narrow the capture to the fields the closure needs, then decide whether each field should be borrowed, moved, or shared through `Arc`. Put clones at named ownership transfers and test the purpose of each copy.
  Source: [Closures](https://codewiki.com/rust/closures/)
- Using `values[index]` with an index derived from external input panics when the index is out of bounds.
  Why: Even if inputs are usually valid, one damaged record can turn a recoverable data error into a process-level failure.
  Source: [Collections](https://codewiki.com/rust/collections/)
- Tests or serializers iterate a `HashMap` or `HashSet`, then commit the observed order to an assertion or external format.
  Why: That order isn't part of the type's contract, even when consecutive local runs happen to agree.
  Source: [Collections](https://codewiki.com/rust/collections/)
- To silence a borrow error, generated code often applies `.clone()` to every key and element before lookup.
  Why: This can conceal an ownership design problem and imply that looking up a `HashMap` requires allocating another `String`.
  Source: [Collections](https://codewiki.com/rust/collections/)
- Calling `contains_key` before `get_mut` or `insert` splits one "present or insert" decision into two steps that may drift apart.
  Why: As the function grows, an early return or another mutation of the same map can slip between those steps.
  Source: [Collections](https://codewiki.com/rust/collections/)
- `or_insert(build_value())` evaluates its argument before `or_insert` runs, so `build_value()` executes even when the key is already present.
  Why: If that constructor logs, performs I/O, or has another side effect, the mistake changes behavior as well as doing needless work.
  Source: [Collections](https://codewiki.com/rust/collections/)
- Do not assume this is safe: you construct an adapter without a consumer.
  Why: Writing `values.iter().map(...)` only constructs another iterator; even if its closure mutates state or prints, it does not run by itself. Fix: If you intend to transform data, pass the result to a consumer such as `collect`; if you only need per-item side effects, prefer a clear `for` loop. Do not append `collect::>()` merely to silence an `unused_must_use` warning because that may add a useless allocation.
  Source: [Iterators](https://codewiki.com/rust/iterators/)
- Do not assume this is safe: you move a collection accidentally.
  Why: Calling `into_iter()` on an owned `Vec` yields each `String` by value and consumes the vector. Generated code often reads the original variable later, triggers `E0382`, then hides the design error by cloning the whole vector. Fix: Use `iter()` when the collection is still needed, `iter_mut()` for in-place updates, and `into_iter()` only when elements should transfer ownership. Call `cloned()` or perform an explicit transformation on only the elements that must cross an owned API boundary.
  Source: [Iterators](https://codewiki.com/rust/iterators/)
- You wrestle with nested references in `filter`.
  Why: `filter` passes a reference to each candidate into its predicate. If the upstream `iter()` already has `Item = &T`, the closure parameter can behave like `&&T`, and elaborate dereferencing is easy to get wrong. Fix: For `Copy` elements, use `.iter().copied()` early so the rest of the pipeline handles `T`. For non-`Copy` elements, retain the borrow and confirm each `Item` through a type annotation or a small named closure instead of adding `*` until compilation succeeds.
  Source: [Iterators](https://codewiki.com/rust/iterators/)
- You swallow data errors with `filter_map(Result::ok)`.
  Why: That expression is appropriate when the contract explicitly says to keep only successes. For imported configuration, money, or identifiers, however, it turns bad records into an apparently complete successful result. Fix: Collect into `Result, _>` when any bad item must fail the operation. When all errors must be accumulated, explicitly partition or fold successes and failures. Write the error policy first, then choose the adapter.
  Source: [Iterators](https://codewiki.com/rust/iterators/)
- You treat a short-circuiting consumer as a stateless query.
  Why: `find`, `any`, and `nth` advance the iterator. A second call on the same named iterator resumes from the remaining position instead of rescanning the source. Fix: Recreate an iterator from a reborrowable source when you need multiple full scans. For a single streaming pass, make the state progression visible in names and tests, covering found, not found, and continued iteration after the call.
  Source: [Iterators](https://codewiki.com/rust/iterators/)
- Do not assume this is safe: you assume `zip` validates equal lengths.
  Why: Standard `zip` stops when either side ends. Extra elements remain on the longer source but do not produce an error, so generated field-pairing code can silently discard data. Fix: If equal length is a business invariant, compare known collection lengths before pairing or use a boundary type that expresses the same-length constraint. Use plain `zip` only when stopping at the shorter side is genuinely the required behavior.
  Source: [Iterators](https://codewiki.com/rust/iterators/)
- Returning a local with an arbitrary `'a`.
  Why: `fn make() -> &'a str` lets the caller choose `'a`, which a `String` created inside the function cannot satisfy; that string is destroyed on return. Fix: Return an owned value such as `String`; only data that truly resides in static storage, such as a string literal or static item, can be returned as a static reference.
  Source: [Lifetime elision and annotations](https://codewiki.com/rust/lifetime-annotations/)
- Binding every parameter to one lifetime.
  Why: If the result comes only from the first input, a shared `'a` lets an unrelated short borrow restrict the result and creates unnecessary compile failures. Fix: Draw the “output comes from” relationship and share a name only between a real source and the output; give other references independent parameters or elided lifetimes.
  Source: [Lifetime elision and annotations](https://codewiki.com/rust/lifetime-annotations/)
- Do not treat `'static` as an extender.
  Why: Adding a `'static` bound, calling `Box::leak`, or hiding data in global state changes resource ownership and may leak memory permanently, but it does not repair the original local-borrow design. Fix: Move owned values across thread and callback boundaries; use scoped APIs for bounded concurrency and static storage only for genuinely process-long data.
  Source: [Lifetime elision and annotations](https://codewiki.com/rust/lifetime-annotations/)
- Ignoring receiver elision.
  Why: The output of `fn choose(&self, candidate: &str) -> &str` is tied to `self` by default, so an implementation that returns `candidate` encounters a lifetime error. Fix: If the output comes from the parameter, write `fn choose(&self, candidate: &'a str) -> &'a str`; preserve the receiver relationship when the output comes from a field.
  Source: [Lifetime elision and annotations](https://codewiki.com/rust/lifetime-annotations/)
- Storing a short borrow in a long-lived object.
  Why: Generated caches, tasks, and handlers often retain a request-body `&str` beyond the request and then try to suppress the error with cloning, `unsafe`, or `'static`. Fix: Decide who owns the data and how long the object must live; store owned data or suitable shared ownership when crossing the source boundary instead of fabricating a lifetime.
  Source: [Lifetime elision and annotations](https://codewiki.com/rust/lifetime-annotations/)
- Adding an arbitrary `'a` to a return type cannot make a slice of a local `String` cross the function return.
  Why: The caller chooses the lifetime parameter, and a local owner cannot satisfy an arbitrary caller-selected region.
  Source: [Lifetimes](https://codewiki.com/rust/lifetimes/)
- Generated code often annotates every reference in a signature with the same `'a`.
  Why: If the result borrows from only one input, an unrelated short-lived argument then restricts the result unnecessarily.
  Source: [Lifetimes](https://codewiki.com/rust/lifetimes/)
- Do not assume this is safe: `move` changes how a closure captures values, but it does not turn a captured `&str` into `&'static str`.
  Why: Moving a reference only moves the reference value; its referent may still expire soon.
  Source: [Lifetimes](https://codewiki.com/rust/lifetimes/)
- NLL computes regions from actual uses and control flow.
  Why: Adding braces mechanically may happen to compile but can hide the later read that really keeps a borrow active; assuming every reference lasts to the block end also rejects valid code in your mental model.
  Source: [Lifetimes](https://codewiki.com/rust/lifetimes/)
- Do not assume this is safe: `Box::leak()` can produce a static reference, but it abandons normal deallocation.
  Why: Leaking per-request data to satisfy a thread or callback bound converts a type error into steadily growing memory use.
  Source: [Lifetimes](https://codewiki.com/rust/lifetimes/)
- Do not treat packages, crates, and modules as synonyms leads to the wrong target count, path root, and visibility boundary.
  Why: One package can build several crates, and every crate has its own module tree.
  Source: [Modules and crates](https://codewiki.com/rust/modules-crates/)
- Do not assume this is safe: creating `src/orders.rs` or `src/orders/` does not declare a module, and `use orders::Order` does not load it.
  Why: Generated code also commonly leaves both `orders.rs` and `orders/mod.rs`, giving one module two candidate sources.
  Source: [Modules and crates](https://codewiki.com/rust/modules-crates/)
- Do not assume this is safe: adding `pub` only to a deeply nested function may not let an external crate call it.
  Why: The original path remains unreachable if an ancestor module is inaccessible; making the entire tree `pub` to silence `E0603` expands the API instead.
  Source: [Modules and crates](https://codewiki.com/rust/modules-crates/)
- Do not assume this is safe: in a binary crate, `crate::some_library_item` starts at that binary's own root module, not the library crate in the same package.
  Why: Sharing a package does not merge the two targets into one crate.
  Source: [Modules and crates](https://codewiki.com/rust/modules-crates/)
- `use module::*` pulls every current public item into the scope.
  Why: A later export can create a collision, and reviewers cannot easily see where a name came from. Preludes and test modules sometimes use glob imports deliberately, but ordinary modules have no default reason to do so.
  Source: [Modules and crates](https://codewiki.com/rust/modules-crates/)
- Saying “assignment transfers ownership” misses the `Copy` case.
  Why: It also encourages explanations based on heap allocation, even though storage location does not decide whether the source remains valid.
  Source: [Moves, partial moves and drops](https://codewiki.com/rust/ownership-rules/)
- Generated code often reacts to `borrow of moved value` by cloning immediately before the move.
  Why: That can duplicate a large buffer, create another reference-counted owner, or hide that the callee only needed read access.
  Source: [Moves, partial moves and drops](https://codewiki.com/rust/ownership-rules/)
- A signature such as `fn length(text: String) -> usize` forces the caller to lose or clone its string even though the implementation only reads it.
  Why: Changing the call site alone cannot repair the exaggerated ownership contract.
  Source: [Moves, partial moves and drops](https://codewiki.com/rust/ownership-rules/)
- Pattern matching, struct update syntax, and direct field access can move one non-`Copy` field.
  Why: Logging the whole struct afterward still fails, even if several untouched fields remain individually usable.
  Source: [Moves, partial moves and drops](https://codewiki.com/rust/ownership-rules/)
- `drop(&guard)` looks explicit but consumes only a copied reference.
  Why: The lock, file, or transaction guard remains owned by its binding and continues to live until that binding ends.
  Source: [Moves, partial moves and drops](https://codewiki.com/rust/ownership-rules/)
- Generated code often passes a `String`, `Vec`, or domain struct by value to a helper and then reads it again in the caller.
  Why: When the compiler reports “borrow of moved value,” the responsibility transfer happened earlier, not necessarily on the reported line.
  Source: [Ownership](https://codewiki.com/rust/ownership/)
- Inserting `.clone()` everywhere may compile while hiding the responsibility boundary.
  Why: It can copy a large buffer, increment a reference count, or duplicate a credential or state snapshot that should stay unique.
  Source: [Ownership](https://codewiki.com/rust/ownership/)
- Do not assume this is safe: “Stack types copy and heap types move” is not a Rust rule.
  Why: A fixed-size value may still own a resource that must be destroyed, while a shared reference can be `Copy` even when it points into heap data.
  Source: [Ownership](https://codewiki.com/rust/ownership/)
- A pattern or field access may move only a struct's `String` field.
  Why: Other fields may remain individually usable, but the whole value is incomplete; adding a `Drop` implementation can also make previously accepted field moves fail.
  Source: [Ownership](https://codewiki.com/rust/ownership/)
- Do not assume this is safe: ordinary scope exits run destructors, but `std::process::exit`, process abort, and strong reference cycles can skip cleanup.
  Why: Ownership also permits safe leaks such as `mem::forget`, so “safe Rust” does not mean “every resource is released promptly.”
  Source: [Ownership](https://codewiki.com/rust/ownership/)
- A wildcard hides enum evolution.
  Why: Generated code often uses `_ => unreachable!()` to remove an exhaustiveness error quickly, but a new valid variant then becomes a production panic instead of a compile-time reminder. Fix: List every variant of a closed enum in your crate. Use `_` only when unknown values genuinely share semantics or the input space is open, and make the fallback behavior safe and observable.
  Source: [Pattern matching](https://codewiki.com/rust/pattern-matching/)
- A bare identifier is mistaken for an outer value.
  Why: In `match code { expected => ... }`, `expected` normally creates a new binding that matches anything and shadows the outer variable, making later arms unreachable. Fix: Compare a runtime value with a guard such as `value if value == expected`. Fixed values should be `const` items or enum variants that resolve as paths, and `unreachable_patterns` warnings should be investigated.
  Source: [Pattern matching](https://codewiki.com/rust/pattern-matching/)
- A guard is assumed to complete exhaustive coverage.
  Why: `Some(value) if value > 0` doesn't cover zero or negative values, and the compiler doesn't prove the logical complement of an arbitrary guard. Fix: Follow guarded arms with a pattern for the remaining structure, such as `Some(value)`, then handle `None`. Test boundary values and the path where the guard is `false`.
  Source: [Pattern matching](https://codewiki.com/rust/pattern-matching/)
- Do not assume this is safe: destructuring moves a field accidentally.
  Why: Binding a `String`, `Vec`, or another non-`Copy` field by value from an owned structure moves it; a generator then often adds an expensive or semantically wrong `.clone()` to patch E0382. Fix: Match `&value` for reading, `&mut value` for mutation, and `value` only when ownership should transfer. After a partial move, use remaining fields separately or refactor around complete consumption instead of using the whole value again.
  Source: [Pattern matching](https://codewiki.com/rust/pattern-matching/)
- `if let` discards a meaningful failure arm.
  Why: `if let Ok(value) = result` with no `else` silently ignores an error and can make an import or configuration failure look successful. Fix: Use `match` or propagate the error when at least two cases affect the result. Reserve `if let` for failures where doing nothing is truly the contract, and make that behavior explicit in tests.
  Source: [Pattern matching](https://codewiki.com/rust/pattern-matching/)
- Moving a `Pin>`, swapping two such variables, or storing one in a `Vec` moves the pointer handle.
  Why: None of these operations moves the `T` in its `Box` allocation, so they do not violate the pinning contract.
  Source: [Pin and Unpin](https://codewiki.com/rust/pin/)
- Do not assume this is safe: wrapping a `String` or an ordinary struct in `Pin` does not make it immovable because those types usually implement `Unpin`.
  Why: Safe code can obtain `&mut T` and then move or replace the value.
  Source: [Pin and Unpin](https://codewiki.com/rust/pin/)
- Storing a field's address in a local `Self` and then passing that value to `Box::pin` creates the pointer before moving the whole struct into the allocation.
  Why: The internal pointer still names the old stack location, so its first dereference may cause undefined behavior.
  Source: [Pin and Unpin](https://codewiki.com/rust/pin/)
- The `&mut Self` returned by `get_unchecked_mut()` can be passed to `mem::replace`, while `map_unchecked_mut()` can expose a structurally pinned field as an ordinary `&mut Field`.
  Why: The compiler trusts the caller's proof and will not protect those paths again.
  Source: [Pin and Unpin](https://codewiki.com/rust/pin/)
- After seeing a `T: Unpin` error, a model may generate `impl Unpin for AddressSensitive {}`.
  Why: This is a safe trait implementation, but an incorrect implementation lets safe callers obtain a movable reference and invalidate the type's internal raw pointers.
  Source: [Pin and Unpin](https://codewiki.com/rust/pin/)
- The pinning guarantee constrains more than ordinary method calls.
  Why: A custom owning pointer that releases or repurposes pinned storage without running `T::drop`, or a destructor that moves a structurally pinned field, also violates the contract.
  Source: [Pin and Unpin](https://codewiki.com/rust/pin/)
- Generated code often turns a borrow error into `Arc>>>>`.
  Why: The result may still fail to cross a thread boundary, while introducing dynamic borrowing, lock poisoning, deadlocks, and more indirection.
  Source: [Smart pointers](https://codewiki.com/rust/smart-pointers/)
- `Rc::clone()` and `Arc::clone()` create another owner of the same allocation.
  Why: If the target is changed through interior mutability or a lock, the other handles observe that same change; they aren't independent snapshots.
  Source: [Smart pointers](https://codewiki.com/rust/smart-pointers/)
- `Rc` and `Arc` don't include cycle detection.
  Why: If a tree stores strong parent and child links, or a registry and subscriber own each other, none of the cycle's targets is destroyed after the external handles disappear.
  Source: [Smart pointers](https://codewiki.com/rust/smart-pointers/)
- Implementing `Deref` for `UserId`, `ValidatedPath`, or `Secret` implicitly exposes the entire string API on the wrapper.
  Why: Callers may bypass domain operations, and source code no longer makes automatic dereferencing obvious.
  Source: [Smart pointers](https://codewiki.com/rust/smart-pointers/)
- Do not assume this is safe: `Drop::drop()` can't return an error, and strong-reference cycles, `mem::forget()`, process aborts, and leaks can prevent or delay expected cleanup.
  Why: A transaction commit, persistence step, or remote acknowledgement hidden only in a destructor loses failure information.
  Source: [Smart pointers](https://codewiki.com/rust/smart-pointers/)
- Do not assume this is safe: a model may use `Box::leak` to turn an owned value into a `'static` reference merely to stop a lifetime error.
  Why: Unless the program has a bounded process-lifetime allocation design, that changes an ownership problem into permanent memory growth.
  Source: [Smart pointers](https://codewiki.com/rust/smart-pointers/)
- Do not assume this is safe: `text.len()` returns UTF-8 bytes, not Unicode scalar values and certainly not user-visible characters.
  Source: [Strings](https://codewiki.com/rust/strings/)
- `&text[..limit]` is safe only when `limit` happens to be a UTF-8 character boundary.
  Why: Non-ASCII input can make it panic.
  Source: [Strings](https://codewiki.com/rust/strings/)
- A function that only reads text but accepts `String` forces callers to move, clone, or add an unnecessary `to_string()`.
  Source: [Strings](https://codewiki.com/rust/strings/)
- Appending to a `String` after taking one of its slices may move the buffer.
  Why: Rust rejects this when the slice is used later.
  Source: [Strings](https://codewiki.com/rust/strings/)
- Do not assume this is safe: `to_lowercase()` can change length and is not the same operation as Unicode normalization, locale-aware collation, or secure identifier comparison.
  Source: [Strings](https://codewiki.com/rust/strings/)
