Skip to content

Commit 0213446

Browse files
committed
progress
1 parent 3be2643 commit 0213446

File tree

3 files changed

+135
-5
lines changed

3 files changed

+135
-5
lines changed

ffi.md

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
% Interfacing with other Languages (FFI)
2+
3+
*Obviously* we'd all love to live in a **glorious** world where everything is
4+
written in Rust, Rust, and More Rust. Tragically, programs have been written
5+
in Not Rust for over 50 years. Crufty enterprises are doomed to
6+
support ancient code bases, and greybeard programmers stuck in their ways
7+
*insist* on writing programs in other languages, even to this day!
8+
9+
In all seriousness, there's a myriad of reasons for your codebase to be a
10+
hybrid of different languages, and Rust is well-designed to interface with
11+
all of them as painlessly as possible. It does this through the tried and
12+
true strategy of all languages: pretend to be C, and understand C.
13+
14+
Thanks to Rust's minimal runtime and C-like semantics, this is about as
15+
painless as FFI with C++. Obviously, most of Rust's features are completely
16+
incompatible with other languages: tagged unions, zero-sized-types, dynamically-
17+
sized types, destructors, methods, traits, references, and lifetimes are all
18+
concepts that you won't be able to expose or accept in your foreign function
19+
interface.
20+
21+
All mapping through C will give you is functions, structs, globals, raw pointers,
22+
and C-like enums. That's it. Rust's default data layouts are also incompatible
23+
with the C layout. See [the section on data layout][data.html] for details.
24+
Long story short: mark FFI structs and enums with `#[repr(C)]`, mark FFI
25+
functions as `extern`.
26+
27+
## Runtime
28+
29+
Rust's runtime is sufficiently minimal that it requires *no* special handling.
30+
You don't need to set anything up. You don't need to tear anything down.
31+
Awesome.
32+
33+
The only runtime detail you *really* need to worry about is unwinding. Rust's
34+
unwinding model is not defined to be incompatible with any particular language.
35+
That means that if you call Rust from another language and it unwinds into the
36+
calling language, this will cause Undefined Behaviour. Similarly, if another
37+
language unwinds into Rust, it will also cause Undefined Behaviour.
38+
39+
Rust can't really do anything about other languages unwinding into it (FFI is unsafe
40+
for a reason!), but you can be a good FFI citizen by catching panics in any
41+
FFI functions you export. Rust provides `thread::catch_panic` for exactly this.
42+
Unfortunately, this API is still unstable.
43+
44+
## libc
45+

lifetimes.md

Lines changed: 88 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ read-write lock.
6060

6161

6262

63+
6364
## Lifetimes
6465

6566
Rust's static checks are managed by the *borrow checker* (borrowck), which tracks
@@ -219,6 +220,77 @@ these are unstable due to their awkward nature and questionable utility.
219220

220221

221222

223+
224+
## Higher-Rank Lifetimes
225+
226+
Generics in Rust generally allow types to be instantiated with arbitrary
227+
associated lifetimes, but this fixes the lifetimes they work with once
228+
instantiated. For almost all types, this is exactly the desired behaviour.
229+
For example slice::Iter can work with arbitrary lifetimes, determined by the
230+
slice that instantiates it. However *once* Iter is instantiated the lifetimes
231+
it works with cannot be changed. It returns references that live for some
232+
particular `'a`.
233+
234+
However some types are more flexible than this. In particular, a single
235+
instantiation of a function can process arbitrary lifetimes:
236+
237+
```rust
238+
fn identity(input: &u8) -> &u8 { input }
239+
```
240+
241+
What is *the* lifetime that identity works with? There is none. If you think
242+
this is "cheating" because functions are statically instantiated, then you need
243+
only consider the equivalent closure:
244+
245+
```rust
246+
let identity = |input: &u8| input;
247+
```
248+
249+
These functions are *higher ranked* over the lifetimes they work with. This means
250+
that they're generic over what they handle *after instantiation*. For most things
251+
this would pose a massive problem, but because lifetimes don't *exist* at runtime,
252+
this is really just a compile-time mechanism. The Fn traits contain sugar that
253+
allows higher-rank lifetimes to simply be expressed by simply omitting lifetimes:
254+
255+
256+
```rust
257+
fn main() {
258+
foo(|input| input);
259+
}
260+
261+
fn foo<F>(f: F)
262+
// F is higher-ranked over the lifetime these references have
263+
where F: Fn(&u8) -> &u8
264+
{
265+
f(&0);
266+
f(&1);
267+
}
268+
```
269+
270+
The desugaring of this is actually unstable:
271+
272+
```
273+
#![feature(unboxed_closures)]
274+
275+
fn main() {
276+
foo(|input| input);
277+
}
278+
279+
fn foo<F>(f: F)
280+
where F: for<'a> Fn<(&'a u8,), Output=&'a u8>
281+
{
282+
f(&0);
283+
f(&1);
284+
}
285+
```
286+
287+
`for<'a>` is how we declare a higher-ranked lifetime. Unfortunately higher-ranked
288+
lifetimes are still fairly new, and are missing a few features to make them
289+
maximally useful outside of the Fn traits.
290+
291+
292+
293+
222294
## Subtyping and Variance
223295

224296
Although Rust doesn't have any notion of inheritance, it *does* include subtyping.
@@ -227,12 +299,15 @@ from scopes, we can partially order them based on an *outlives* relationship. We
227299
can even express this as a generic bound: `T: 'a` specifies that `T` *outlives* `'a`.
228300

229301
We can then define subtyping on lifetimes in terms of lifetimes: `'a : 'b` implies
230-
`'a <: b` -- if `'a' outlives `'b`, then `'a` is a subtype of `'b`. This is a very
302+
`'a <: b` -- if `'a` outlives `'b`, then `'a` is a subtype of `'b`. This is a very
231303
large source of confusion, because a bigger scope is a *sub type* of a smaller scope.
232304
This does in fact make sense. The intuitive reason for this is that if you expect an
233305
`&'a u8`, then it's totally fine for me to hand you an `&'static u8`, in the same way
234306
that if you expect an Animal in Java, it's totally fine for me to hand you a Cat.
235307

308+
(Note, the subtyping relationship and typed-ness of lifetimes is a fairly arbitrary
309+
construct that some disagree with. I just find that it simplifies this analysis.)
310+
236311
Variance is where things get really harsh.
237312

238313
Variance is a property that *type constructors* have. A type constructor in Rust
@@ -278,7 +353,7 @@ fn overwrite<T: Copy>(input: &mut T, new: &mut T) {
278353

279354
The signature of `overwrite` is clearly valid: it takes mutable references to two values
280355
of the same type, and replaces one with the other. We have seen already that `&` is
281-
covariant, and `'static` is a subtype of *any* `'a', so `&'static str` is a
356+
covariant, and `'static` is a subtype of *any* `'a`, so `&'static str` is a
282357
subtype of `&'a str`. Therefore, if `&mut` was
283358
*also* covariant, then the lifetime of the `&'static str` would successfully be
284359
"shrunk" down to the shorter lifetime of the string, and `replace` would be
@@ -341,8 +416,16 @@ respectively.
341416
## PhantomData and PhantomFn
342417

343418
This is all well and good for the types the standard library provides, but
344-
how is variance determined for type that *you* define? The variance of a type
345-
over its generic arguments is determined by how they're stored.
419+
how is variance determined for type that *you* define? A struct is, informally
420+
speaking, covariant over all its fields (and an enum over its variants). This
421+
basically means that it inherits the variance of its fields. If a struct `Foo`
422+
has a generic argument `A` that is used in a field `a`, then Foo's variance
423+
over `A` is exactly `a`'s variance. However this is complicated if `A` is used
424+
in multiple fields.
425+
426+
* If all uses of A are covariant, then Foo is covariant over A
427+
* If all uses of A are contravariant, then Foo is contravariant over A
428+
* Otherwise, Foo is invariant over A
346429

347430
```rust
348431
struct Foo<'a, 'b, A, B, C, D, E, F, G, H> {
@@ -360,7 +443,7 @@ struct Foo<'a, 'b, A, B, C, D, E, F, G, H> {
360443

361444
However when working with unsafe code, we can often end up in a situation where
362445
types or lifetimes are logically associated with a struct, but not actually
363-
reachable. This most commonly occurs with lifetimes. For instance, the `Iter`
446+
part of a field. This most commonly occurs with lifetimes. For instance, the `Iter`
364447
for `&'a [T]` is (approximately) defined as follows:
365448

366449
```

no_std.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
% Eliminating the Runtime (no_std)
2+

0 commit comments

Comments
 (0)