@@ -12,7 +12,7 @@ The brief summary is:
12
12
* Unsafe APIs should be made into methods or static functions in the same cases
13
13
that safe APIs would be.
14
14
15
- * ` raw ` submodules should be used only to provide APIs directly on low-level
15
+ * ` raw ` submodules should be used only to * define * explicit low-level
16
16
representations.
17
17
18
18
# Motivation
@@ -30,10 +30,10 @@ provides:
30
30
as well as a ` from_utf8 ` variant that does not actually check for utf8
31
31
validity.
32
32
33
- The problem is that currently, there is no consistent guideline about which of
34
- these APIs should live as methods/static functions associated with a type, and
35
- which should live in a ` raw ` submodule. Both forms appear throughout the
36
- standard library.
33
+ The problem is that currently, there is no clear/ consistent guideline about
34
+ which of these APIs should live as methods/static functions associated with a
35
+ type, and which should live in a ` raw ` submodule. Both forms appear throughout
36
+ the standard library.
37
37
38
38
# Detailed design
39
39
@@ -42,35 +42,66 @@ The proposed convention is:
42
42
* When an unsafe function/method is clearly "about" a certain type (as a way of
43
43
constructing, destructuring, or modifying values of that type), it should be a
44
44
method or static function on that type. This is the same as the convention for
45
- placement of safe functions/methods.
45
+ placement of safe functions/methods. So functions like
46
+ ` string::raw::from_parts ` would become static functions on ` String ` .
46
47
47
- * When an unsafe function/method is specifically for producing or consuming the
48
- underlying representation of a data structure (which is otherwise private),
49
- the API should use ` raw ` in its name. Specifically, ` from_raw_parts ` is the
50
- typical name used for constructing a value from e.g. a pointer-based
51
- representation.
48
+ * ` raw ` submodules should only be used to * define* low-level
49
+ types/representations (and methods/functions on them). Methods for converting
50
+ to/from such low-level types should be available directly on the high-level
51
+ types. Examples: ` core::raw ` , ` sync::raw ` .
52
52
53
- * When an unsafe function/method is an unchecked variant of an otherwise safe
54
- API, it should be marked using an ` _unchecked ` suffix.
53
+ The benefits are:
55
54
56
- * ` raw ` submodules should only be used to provide APIs directly on low-level
57
- representations, separately from functions/methods for converting to/from such
58
- raw representations.
55
+ * * Ergonomics* . You can gain easy access to unsafe APIs merely by having a value
56
+ of the type (or, for static functions, importing the type).
59
57
60
- The benefit to moving unsafe APIs into methods (resp. static functions) is the
61
- usual one: you can gain easy access to these APIs merely by having a value of
62
- the type (resp. importing the type).
58
+ * * Consistency and simplicity* . The rules for placement of unsafe APIs are the
59
+ same as those for safe APIs.
63
60
64
61
The perspective here is that marking APIs ` unsafe ` is enough to deter their use
65
62
in ordinary situations; they don't need to be further distinguished by placement
66
63
into a separate module.
67
64
65
+ There are also some naming conventions to go along with unsafe static functions
66
+ and methods:
67
+
68
+ * When an unsafe function/method is an unchecked variant of an otherwise safe
69
+ API, it should be marked using an ` _unchecked ` suffix.
70
+
71
+ For example, the ` String ` module should provide both ` from_utf8 ` and
72
+ ` from_utf8_unchecked ` constructors, where the latter does not actually check
73
+ the utf8 encoding. The ` string::raw::slice_bytes ` and
74
+ ` string::raw::slice_unchecked ` functions should be merged into a single
75
+ ` slice_unchecked ` method on strings that checks neither bounds nor utf8
76
+ boundaries.
77
+
78
+ * When an unsafe function/method produces or consumes a low-level representation
79
+ of a data structure, the API should use ` raw ` in its name. Specifically,
80
+ ` from_raw_parts ` is the typical name used for constructing a value from e.g. a
81
+ pointer-based representation.
82
+
83
+ * Otherwise, * consider* using a name that suggests * why* the API is unsafe. In
84
+ some cases, like ` String::as_mut_vec ` , other stronger conventions apply, and the
85
+ ` unsafe ` qualifier on the signature (together with API documentation) is
86
+ enough.
87
+
88
+ The unsafe methods and static functions for a given type should be placed in
89
+ their own ` impl ` block, at the end of the module defining the type; this will
90
+ ensure that they are grouped together in rustdoc. (Thanks @kballard for the
91
+ suggestion.)
92
+
68
93
# Drawbacks
69
94
70
95
One potential drawback of these conventions is that the documentation for a
71
96
module will be cluttered with rarely-used ` unsafe ` APIs, whereas the ` raw `
72
97
submodule approach neatly groups these APIs. But rustdoc could easily be
73
- changed to either hide or separate out ` unsafe ` APIs by default.
98
+ changed to either hide or separate out ` unsafe ` APIs by default, and in the
99
+ meantime the ` impl ` block grouping should help.
100
+
101
+ More specifically, the convention of placing unsafe constructors in ` raw ` makes
102
+ them very easy to find. But the usual ` from_ ` convention, together with the
103
+ naming conventions suggested above, should make it fairly easy to discover such
104
+ constructors even when they're supplied directly as static functions.
74
105
75
106
More generally, these conventions give ` unsafe ` APIs more equal status with safe
76
107
APIs. Whether this is a * drawback* depends on your philosophy about the status
@@ -81,7 +112,7 @@ is no reason to penalize its ergonomics given that it's opt-in anyway.*
81
112
82
113
# Alternatives
83
114
84
- There are two main alternatives:
115
+ There are a few alternatives:
85
116
86
117
* Rather than providing unsafe APIs directly as methods/static functions, they
87
118
could be grouped into a single extension trait. For example, the ` String ` type
@@ -93,6 +124,21 @@ There are two main alternatives:
93
124
them ` unsafe ` ), and given that rustdoc could easily provide API grouping, it's
94
125
unclear exactly what the benefit is.
95
126
127
+ * ([ Suggested by @kballard ] ( https://github.com/rust-lang/rfcs/pull/240#issuecomment-55635468 ) ):
128
+
129
+ > Use ` raw ` for functions that construct a value of the type without checking
130
+ > for one or more invariants.
131
+
132
+ The advantage is that it's easy to find such invariant-ignoring functions. The
133
+ disadvantage is that their ergonomics is worsened, since they much be
134
+ separately imported or referenced through a lengthy path:
135
+
136
+ ``` rust
137
+ // Compare the ergonomics:
138
+ string :: raw :: slice_unchecked (some_string , start , end )
139
+ some_string . slice_unchecked (start , end )
140
+ ```
141
+
96
142
* Use ` raw ` submodules to group together * all* manipulation of low-level
97
143
representations. No module in ` std ` currently does this; existing modules
98
144
provide some free functions in ` raw ` , and some unsafe methods, without a clear
0 commit comments