[3](https://rust-lang.github.io/rust-clippy/master/index.html#map_clone) or [4](https://rust-lang.github.io/rust-clippy/master/index.html#clone_double_ref).
[3](https://rust-lang.github.io/rust-clippy/master/index.html#map_clone) or
- If the API between types does not change -- only the behavior does -- then
- If the API between types does not change -- only the behavior does -- then the
the [Strategy Pattern](../patterns/behavioural/strategy.md) is better used
[Strategy Pattern](../patterns/behavioural/strategy.md) is better used
instead.
instead.
## See also
## See also
@ -239,8 +238,8 @@ improve in the future.
This pattern is used throughout the standard library:
This pattern is used throughout the standard library:
- `Vec<u8>` can be cast from a String, unlike every other type of `Vec<T>`.[^1]
- `Vec<u8>` can be cast from a String, unlike every other type of `Vec<T>`.[^1]
- They can also be cast into a binary heap, but only if they contain a type
- They can also be cast into a binary heap, but only if they contain a type that
that implements the `Ord` trait.[^2]
implements the `Ord` trait.[^2]
- The `to_string` method was specialized for `Cow` only of type `str`.[^3]
- The `to_string` method was specialized for `Cow` only of type `str`.[^3]
It is also used by several popular crates to allow API flexibility:
It is also used by several popular crates to allow API flexibility:
@ -248,8 +247,8 @@ It is also used by several popular crates to allow API flexibility:
- The `embedded-hal` ecosystem used for embedded devices makes extensive use of
- The `embedded-hal` ecosystem used for embedded devices makes extensive use of
this pattern. For example, it allows statically verifying the configuration of
this pattern. For example, it allows statically verifying the configuration of
device registers used to control embedded pins. When a pin is put into a mode,
device registers used to control embedded pins. When a pin is put into a mode,
it returns a `Pin<MODE>` struct, whose generic determines the functions
it returns a `Pin<MODE>` struct, whose generic determines the functions usable
usable in that mode, which are not on the `Pin` itself. [^4]
in that mode, which are not on the `Pin` itself. [^4]
- The `hyper` HTTP client library uses this to expose rich APIs for different
- The `hyper` HTTP client library uses this to expose rich APIs for different
pluggable requests. Clients with different connectors have different methods
pluggable requests. Clients with different connectors have different methods
@ -260,11 +259,14 @@ It is also used by several popular crates to allow API flexibility:
internal state or invariant -- is implemented in Rust using the same basic
internal state or invariant -- is implemented in Rust using the same basic
concept, and a slightly different technique. [^6]
concept, and a slightly different technique. [^6]
[^1]: See: [impl From\<CString\> for Vec\<u8\>](https://doc.rust-lang.org/1.59.0/src/std/ffi/c_str.rs.html#803-811)
[^1]: See:
[impl From\<CString\> for Vec\<u8\>](https://doc.rust-lang.org/1.59.0/src/std/ffi/c_str.rs.html#803-811)
[^2]: See: [impl\<T\> From\<Vec\<T, Global\>\> for BinaryHeap\<T\>](https://doc.rust-lang.org/stable/src/alloc/collections/binary_heap.rs.html#1345-1354)
[^2]: See:
[impl\<T: Ord\> FromIterator\<T\> for BinaryHeap\<T\>](https://web.archive.org/web/20201030132806/https://doc.rust-lang.org/stable/src/alloc/collections/binary_heap.rs.html#1330-1335)
[^3]: See: [impl\<'\_\> ToString for Cow\<'\_, str>](https://doc.rust-lang.org/stable/src/alloc/string.rs.html#2235-2240)
[^3]: See:
[impl\<'\_\> ToString for Cow\<'\_, str>](https://doc.rust-lang.org/stable/src/alloc/string.rs.html#2235-2240)
When working with enums, we may want to change an enum value in place, perhaps
When working with enums, we may want to change an enum value in place, perhaps
to another variant. This is usually done in two phases to keep the borrow
to another variant. This is usually done in two phases to keep the borrow
checker happy. In the first phase, we observe the existing value and look at
checker happy. In the first phase, we observe the existing value and look at its
its parts to decide what to do next. In the second phase we may conditionally
parts to decide what to do next. In the second phase we may conditionally change
change the value (as in the example above).
the value (as in the example above).
The borrow checker won't allow us to take out `name` of the enum (because
The borrow checker won't allow us to take out `name` of the enum (because
_something_ must be there.) We could of course `.clone()` name and put the clone
*something* must be there.) We could of course `.clone()` name and put the clone
into our `MyEnum::B`, but that would be an instance of the [Clone to satisfy the borrow checker](../anti_patterns/borrow_clone.md) anti-pattern. Anyway, we
into our `MyEnum::B`, but that would be an instance of the
can avoid the extra allocation by changing `e` with only a mutable borrow.
[Clone to satisfy the borrow checker](../anti_patterns/borrow_clone.md)
anti-pattern. Anyway, we can avoid the extra allocation by changing `e` with
only a mutable borrow.
`mem::take` lets us swap out the value, replacing it with it's default value,
`mem::take` lets us swap out the value, replacing it with it's default value,
and returning the previous value. For `String`, the default value is an empty
and returning the previous value. For `String`, the default value is an empty
`String`, which does not need to allocate. As a result, we get the original
`String`, which does not need to allocate. As a result, we get the original
`name`_as an owned value_. We can then wrap this in another enum.
`name`*as an owned value*. We can then wrap this in another enum.
**NOTE:** `mem::replace` is very similar, but allows us to specify what to
**NOTE:** `mem::replace` is very similar, but allows us to specify what to
replace the value with. An equivalent to our `mem::take` line would be
replace the value with. An equivalent to our `mem::take` line would be
`mem::replace(name, String::new())`.
`mem::replace(name, String::new())`.
Note, however, that if we are using an `Option` and want to replace its
Note, however, that if we are using an `Option` and want to replace its value
value with a `None`, `Option`’s `take()` method provides a shorter and
with a `None`, `Option`’s `take()` method provides a shorter and more idiomatic
more idiomatic alternative.
alternative.
## Advantages
## Advantages
@ -86,13 +88,13 @@ Look ma, no allocation! Also you may feel like Indiana Jones while doing it.
## Disadvantages
## Disadvantages
This gets a bit wordy. Getting it wrong repeatedly will make you hate the
This gets a bit wordy. Getting it wrong repeatedly will make you hate the borrow
borrow checker. The compiler may fail to optimize away the double store,
checker. The compiler may fail to optimize away the double store, resulting in
resulting in reduced performance as opposed to what you'd do in unsafe
reduced performance as opposed to what you'd do in unsafe languages.
languages.
Furthermore, the type you are taking needs to implement the [`Default` trait](./default.md). However, if the type you're working with doesn't
Furthermore, the type you are taking needs to implement the
implement this, you can instead use `mem::replace`.
[`Default` trait](./default.md). However, if the type you're working with
doesn't implement this, you can instead use `mem::replace`.
## Discussion
## Discussion
@ -107,5 +109,6 @@ like Indiana Jones, replacing the artifact with a bag of sand.
## See also
## See also
This gets rid of the [Clone to satisfy the borrow checker](../anti_patterns/borrow_clone.md)
This gets rid of the
[Clone to satisfy the borrow checker](../anti_patterns/borrow_clone.md)
When designing APIs in Rust which are exposed to other languages, there are some
When designing APIs in Rust which are exposed to other languages, there are some
important design principles which are contrary to normal Rust API design:
important design principles which are contrary to normal Rust API design:
1. All Encapsulated types should be _owned_ by Rust, _managed_ by the user,
1. All Encapsulated types should be *owned* by Rust, *managed* by the user, and
and _opaque_.
*opaque*.
2. All Transactional data types should be _owned_ by the user, and _transparent_.
2. All Transactional data types should be *owned* by the user, and
*transparent*.
3. All library behavior should be functions acting upon Encapsulated types.
3. All library behavior should be functions acting upon Encapsulated types.
4. All library behavior should be encapsulated into types not based on structure,
4. All library behavior should be encapsulated into types not based on
but _provenance/lifetime_.
structure, but *provenance/lifetime*.
## Motivation
## Motivation
Rust has built-in FFI support to other languages.
Rust has built-in FFI support to other languages. It does this by providing a
It does this by providing a way for crate authors to provide C-compatible APIs
way for crate authors to provide C-compatible APIs through different ABIs
through different ABIs (though that is unimportant to this practice).
(though that is unimportant to this practice).
Well-designed Rust FFI follows C API design principles, while compromising the
Well-designed Rust FFI follows C API design principles, while compromising the
design in Rust as little as possible. There are three goals with any foreign API:
design in Rust as little as possible. There are three goals with any foreign
API:
1. Make it easy to use in the target language.
1. Make it easy to use in the target language.
2. Avoid the API dictating internal unsafety on the Rust side as much as possible.
2. Avoid the API dictating internal unsafety on the Rust side as much as
3. Keep the potential for memory unsafety and Rust `undefined behaviour` as small
possible.
as possible.
3. Keep the potential for memory unsafety and Rust `undefined behaviour` as
small as possible.
Rust code must trust the memory safety of the foreign language beyond a certain
Rust code must trust the memory safety of the foreign language beyond a certain
point. However, every bit of `unsafe` code on the Rust side is an opportunity for
point. However, every bit of `unsafe` code on the Rust side is an opportunity
bugs, or to exacerbate `undefined behaviour`.
for bugs, or to exacerbate `undefined behaviour`.
For example, if a pointer provenance is wrong, that may be a segfault due to
For example, if a pointer provenance is wrong, that may be a segfault due to
invalid memory access. But if it is manipulated by unsafe code, it could become
invalid memory access. But if it is manipulated by unsafe code, it could become
full-blown heap corruption.
full-blown heap corruption.
The Object-Based API design allows for writing shims that have good memory safety
The Object-Based API design allows for writing shims that have good memory
characteristics, and a clean boundary of what is safe and what is `unsafe`.
safety characteristics, and a clean boundary of what is safe and what is
`unsafe`.
## Code Example
## Code Example
The POSIX standard defines the API to access an on-file database, known as [DBM](https://web.archive.org/web/20210105035602/https://www.mankier.com/0p/ndbm.h).
The POSIX standard defines the API to access an on-file database, known as
We are utilizing [mdbook-i18n-helper](https://github.com/google/mdbook-i18n-helpers).
We are utilizing
Please read up on how to _add_ and _update_ translations in [their repository](https://github.com/google/mdbook-i18n-helpers#creating-and-updating-translations)