]> git.proxmox.com Git - rustc.git/blob - src/doc/style/safety/lib-guarantees.md
Imported Upstream version 1.6.0+dfsg1
[rustc.git] / src / doc / style / safety / lib-guarantees.md
1 % Library-level guarantees
2
3 Most libraries rely on internal invariants, e.g. about their data, resource
4 ownership, or protocol states. In Rust, broken invariants cannot produce
5 segfaults, but they can still lead to wrong answers.
6
7 ### Provide library-level guarantees whenever practical. **[FIXME: needs RFC]**
8
9 Library-level invariants should be turned into guarantees whenever
10 practical. They should hold no matter what the client does, modulo
11 explicit opt-outs. Depending on the kind of invariant, this can be
12 achieved through a combination of static and dynamic enforcement, as
13 described below.
14
15 #### Static enforcement:
16
17 Guaranteeing invariants almost always requires _hiding_,
18 i.e. preventing the client from directly accessing or modifying
19 internal data.
20
21 For example, the representation of the `str` type is hidden,
22 which means that any value of type `str` must have been produced
23 through an API under the control of the `str` module, and these
24 APIs in turn ensure valid utf-8 encoding.
25
26 Rust's type system makes it possible to provide guarantees even while
27 revealing more of the representation than usual. For example, the
28 `as_bytes()` method on `&str` gives a _read-only_ view into the
29 underlying buffer, which cannot be used to violate the utf-8 property.
30
31 #### Dynamic enforcement:
32
33 Malformed inputs from the client are hazards to library-level
34 guarantees, so library APIs should validate their input.
35
36 For example, `std::str::from_utf8_owned` attempts to convert a `u8`
37 slice into an owned string, but dynamically checks that the slice is
38 valid utf-8 and returns `Err` if not.
39
40 See
41 [the discussion on input validation](../features/functions-and-methods/input.md)
42 for more detail.
43
44
45 ### Prefer static enforcement of guarantees. **[FIXME: needs RFC]**
46
47 Static enforcement provides two strong benefits over dynamic enforcement:
48
49 * Bugs are caught at compile time.
50 * There is no runtime cost.
51
52 Sometimes purely static enforcement is impossible or impractical. In these
53 cases, a library should check as much as possible statically, but defer to
54 dynamic checks where needed.
55
56 For example, the `std::string` module exports a `String` type with the guarantee
57 that all instances are valid utf-8:
58
59 * Any _consumer_ of a `String` is statically guaranteed utf-8 contents. For example,
60 the `append` method can push a `&str` onto the end of a `String` without
61 checking anything dynamically, since the existing `String` and `&str` are
62 statically guaranteed to be in utf-8.
63
64 * Some _producers_ of a `String` must perform dynamic checks. For example, the
65 `from_utf8` function attempts to convert a `Vec<u8>` into a `String`, but
66 dynamically checks that the contents are utf-8.
67
68 ### Provide opt-outs with caution; make them explicit. **[FIXME: needs RFC]**
69
70 Providing library-level guarantees sometimes entails inconvenience (for static
71 checks) or overhead (for dynamic checks). So it is sometimes desirable to allow
72 clients to sidestep this checking, while promising to use the API in a way that
73 still provides the guarantee. Such escape hatches should only be introduced when
74 there is a demonstrated need for them.
75
76 It should be trivial for clients to audit their use of the library for
77 escape hatches.
78
79 See
80 [the discussion on input validation](../features/functions-and-methods/input.md)
81 for conventions on marking opt-out functions.