[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
the [Strategy Pattern](../patterns/behavioural/strategy.md) is better used
- If the API between types does not change -- only the behavior does -- then the
[Strategy Pattern](../patterns/behavioural/strategy.md) is better used
instead.
## See also
@ -239,8 +238,8 @@ improve in the future.
This pattern is used throughout the standard library:
- `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
that implements the `Ord` trait.[^2]
- They can also be cast into a binary heap, but only if they contain a type that
implements the `Ord` trait.[^2]
- 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:
@ -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
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,
it returns a `Pin<MODE>` struct, whose generic determines the functions
usable in that mode, which are not on the `Pin` itself. [^4]
it returns a `Pin<MODE>` struct, whose generic determines the functions usable
in that mode, which are not on the `Pin` itself. [^4]
- The `hyper` HTTP client library uses this to expose rich APIs for different
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
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
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
its parts to decide what to do next. In the second phase we may conditionally
change the value (as in the example above).
checker happy. In the first phase, we observe the existing value and look at its
parts to decide what to do next. In the second phase we may conditionally change
the value (as in the example above).
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
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
can avoid the extra allocation by changing `e` with only a mutable borrow.
*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 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,
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
`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
replace the value with. An equivalent to our `mem::take` line would be
`mem::replace(name, String::new())`.
Note, however, that if we are using an `Option` and want to replace its
value with a `None`, `Option`’s `take()` method provides a shorter and
more idiomatic alternative.
Note, however, that if we are using an `Option` and want to replace its value
with a `None`, `Option`’s `take()` method provides a shorter and more idiomatic
alternative.
## Advantages
@ -86,13 +88,13 @@ Look ma, no allocation! Also you may feel like Indiana Jones while doing it.
## Disadvantages
This gets a bit wordy. Getting it wrong repeatedly will make you hate the
borrow checker. The compiler may fail to optimize away the double store,
resulting in reduced performance as opposed to what you'd do in unsafe
languages.
This gets a bit wordy. Getting it wrong repeatedly will make you hate the borrow
checker. The compiler may fail to optimize away the double store, resulting in
reduced performance as opposed to what you'd do in unsafe 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
implement this, you can instead use `mem::replace`.
Furthermore, the type you are taking needs to implement the
[`Default` trait](./default.md). However, if the type you're working with
doesn't implement this, you can instead use `mem::replace`.
## Discussion
@ -107,5 +109,6 @@ like Indiana Jones, replacing the artifact with a bag of sand.
## 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
important design principles which are contrary to normal Rust API design:
1. All Encapsulated types should be _owned_ by Rust, _managed_ by the user,
and _opaque_.
2. All Transactional data types should be _owned_ by the user, and _transparent_.
1. All Encapsulated types should be *owned* by Rust, *managed* by the user, and
*opaque*.
2. All Transactional data types should be *owned* by the user, and
*transparent*.
3. All library behavior should be functions acting upon Encapsulated types.
4. All library behavior should be encapsulated into types not based on structure,
but _provenance/lifetime_.
4. All library behavior should be encapsulated into types not based on
structure, but *provenance/lifetime*.
## Motivation
Rust has built-in FFI support to other languages.
It does this by providing a way for crate authors to provide C-compatible APIs
through different ABIs (though that is unimportant to this practice).
Rust has built-in FFI support to other languages. It does this by providing a
way for crate authors to provide C-compatible APIs through different ABIs
(though that is unimportant to this practice).
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.
2. Avoid the API dictating internal unsafety on the Rust side as much as possible.
3. Keep the potential for memory unsafety and Rust `undefined behaviour` as small
as possible.
2. Avoid the API dictating internal unsafety on the Rust side as much 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
point. However, every bit of `unsafe` code on the Rust side is an opportunity for
bugs, or to exacerbate `undefined behaviour`.
point. However, every bit of `unsafe` code on the Rust side is an opportunity
for bugs, or to exacerbate `undefined behaviour`.
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
full-blown heap corruption.
The Object-Based API design allows for writing shims that have good memory safety
characteristics, and a clean boundary of what is safe and what is `unsafe`.
The Object-Based API design allows for writing shims that have good memory
safety characteristics, and a clean boundary of what is safe and what is
`unsafe`.
## 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).
Please read up on how to _add_ and _update_ translations in [their repository](https://github.com/google/mdbook-i18n-helpers#creating-and-updating-translations)