Slide 1

Slide 1 text

No content

Slide 2

Slide 2 text

Enabler

Slide 3

Slide 3 text

No content

Slide 4

Slide 4 text

#Disrupt

Slide 5

Slide 5 text

No content

Slide 6

Slide 6 text

Daemon Collector

Slide 7

Slide 7 text

No content

Slide 8

Slide 8 text

No content

Slide 9

Slide 9 text

No content

Slide 10

Slide 10 text

C is the Lingua Franca (and it's where the bugs in Skylight can still live)

Slide 11

Slide 11 text

The Rust Compiler Protects Us From Low-Level Bugs

Slide 12

Slide 12 text

Rust Helps Us Communicate Fundamental Constraints

Slide 13

Slide 13 text

C Code char*  trace_name(Trace*  trace)  {      /*  impl  */   }   //  Questions:   //     //  *  Can  trace_name  retain  an  alias  to  the  Trace*?   //  *  Can  trace_name  mutate  the  Trace*?   //  *  Can  a  caller  mutate  the  Trace*  during  trace_name?   //  *  Who  is  responsible  to  freeing  the  char*?

Slide 14

Slide 14 text

Rust Code fn  trace_name(trace:  &Trace)  -­‐>  String  {      /*  impl  */   }   //  Questions:   //     //  *  Can  trace_name  retain  an  alias  to  the  Trace?  No.   //  *  Can  trace_name  mutate  the  Trace?  No.   //  *  Can  a  caller  mutate  the  Trace  during  trace_name?  No.   //  *  Who  is  responsible  to  freeing  the  String?  The  caller.

Slide 15

Slide 15 text

In scope: Calling Rust from C

Slide 16

Slide 16 text

Out of scope: Calling C from From Rust

Slide 17

Slide 17 text

Extern Rust Functions #[no_mangle]   extern  "C"  fn  trace_name(trace:  &Trace)  -­‐>  String  {
    /*  impl  */
 }
 
 //  Questions:   //     //  *  Can  trace_name  retain  an  alias  to  the  Trace?  No.   //  *  Can  trace_name  mutate  the  Trace?  No.   //  *  Can  a  caller  mutate  the  Trace  during  trace_name?  No.   //  *  Who  is  responsible  to  freeing  the  String?  The  caller.   //  *  TLDR:  The  same  story!

Slide 18

Slide 18 text

Rust is a DSL for describing ownership concepts that you have to think about when writing C or C++ Me, Now

Slide 19

Slide 19 text

The Concepts of Ownership Are Fundamental to Systems Programming

Slide 20

Slide 20 text

Rust Gives Us The Vocabulary to Talk About It

Slide 21

Slide 21 text

Calling Rust From C extern  "C"  fn  trace_id(trace:  &Trace)  -­‐>  u64; uint64_t  get_trace_id(Trace*  trace)  {      return  trace_id(trace);   }

Slide 22

Slide 22 text

The Process 1. Identify and implement the shared type definitions in Rust and C 2. Use Rust types to flesh out the ownership and mutability rules 3. Decide how to express and "enforce" the requirements from C

Slide 23

Slide 23 text

Step 1. Identify and implement the shared type definitions in Rust and C

Slide 24

Slide 24 text

Calling Rust From C extern  "C"  fn  trace_id(trace:  &Trace)  -­‐>  u64;  

Slide 25

Slide 25 text

Calling Rust From C extern  "C"  fn  trace_id(trace:  &Trace)  -­‐>  u64;   What is this type in terms of C?

Slide 26

Slide 26 text

Calling Rust From C extern  "C"  fn  trace_id(trace:  &Trace)  -­‐>  u64;   What is this type in terms of C? Go-to answer for simple types:
 typedef  u64  uint64_t;

Slide 27

Slide 27 text

Calling Rust From C extern  "C"  fn  trace_id(trace:  &Trace)  -­‐>  u64;   uint64_t  trace_id(Trace*  trace); What is this type in terms of C? Go-to answer for simple types:
 typedef  u64  uint64_t;

Slide 28

Slide 28 text

Calling Rust From C extern  "C"  fn  new_trace()  -­‐>  Box;  

Slide 29

Slide 29 text

Calling Rust From C extern  "C"  fn  new_trace()  -­‐>  Box;   What is this type in terms of C?

Slide 30

Slide 30 text

Calling Rust From C extern  "C"  fn  new_trace()  -­‐>  Box;   What is this type in terms of C? Go-to answer for structures:
 typedef  Trace  void  *;

Slide 31

Slide 31 text

Calling Rust From C extern  "C"  fn  new_trace()  -­‐>  Box;   typedef  void*  Trace;   Trace  new_trace(); What is this type in terms of C? Go-to answer for structures:
 typedef  Trace  void  *;

Slide 32

Slide 32 text

Simple Example struct  Point  {      x:  i64,      y:  i64   }   #[no_mangle]   extern  "C"  fn  new_point(x:  i64,  y:  i64)  -­‐>  Box  {      Box::new(Point  {  x:  x,  y:  y  })   }   #[no_mangle]   extern  "C"  fn  line_len(p1:  &Point,  p2:  &Point)  -­‐>  f64  {      /*  impl  */   }

Slide 33

Slide 33 text

Simple Scaffolding From C typedef  void*  Point;   typedef  int64_t  i64;   typedef  double  f64;   Point  new_point(i64  x,  i64  y);   f64  line_len(Point  p1,  Point  p2);   Point  make_point(i64  x,  i64  y)  {      return  new_point(x,  y);   }   f64  calculate_len(Point  p1,  Point  p2)  {      return  line_len(p1,  p2);   }

Slide 34

Slide 34 text

Simple Mapping / My Opinion Rust C Portable Copy Types u32,  i64,  usize uint32_t,  int64_t,  uintptr_t Your Structures Box typedef  to  void  * Borrowed Structures &T typedef  to  void  * Strings and Vectors String  /  Vec  /  &str  /  &[T] Custom Transport

Slide 35

Slide 35 text

(In practice you usually end up wrapping the Rust pointer in your language's "object")

Slide 36

Slide 36 text

Step 2.
 Use Rust types to flesh out the ownership and mutability rules

Slide 37

Slide 37 text

#[no_mangle]   extern  "C"  fn  line_len(p1:  &Point,  p2:  &Point)  -­‐>  f64  {      /*  impl  */   }

Slide 38

Slide 38 text

What we did so far #[no_mangle]   extern  "C"  fn  line_len(p1:  &Point,  p2:  &Point)  -­‐>  f64  {      /*  impl  */   } typedef  void*  Point;   typedef  double  f64;   f64  line_len(Point  p1,  Point  p2);

Slide 39

Slide 39 text

What we did so far #[no_mangle]   extern  "C"  fn  line_len(p1:  &Point,  p2:  &Point)  -­‐>  f64  {      /*  impl  */   } typedef  void*  Point;   typedef  double  f64;   f64  line_len(Point  p1,  Point  p2);

Slide 40

Slide 40 text

What we did so far #[no_mangle]   extern  "C"  fn  line_len(p1:  &Point,  p2:  &Point)  -­‐>  f64  {      /*  impl  */   } typedef  void*  Point;   typedef  double  f64;   f64  line_len(Point  p1,  Point  p2);

Slide 41

Slide 41 text

And now, docs! typedef  void*  Point;   typedef  double  f64;   /**      line_len  takes  two  Point  structs.  You  can  rely  on  the  fact  that  it        will  not  create  aliases  to  the  Points  that  outlive  the  invocation.      Point  should  be  memory  that  is  valid  and  immutable  for  the  duration      of  the  call  to  the  line_len  function.   */   f64  line_len(const  Point  p1,  const  Point  p2);

Slide 42

Slide 42 text

Mapping typedef  void*  Poing;   typedef  double  f64;   /**      line_len  takes  two  Point  structs.  You  can  rely  on  the  fact  that  it        will  not  create  aliases  to  the  Points  that  outlive  the  invocation.      Point  should  be  memory  that  is  valid  and  immutable  for  the  duration      of  the  call  to  the  line_len  function.   */   f64  line_len(const  Point  p1,  const  Point  p2); #[no_mangle]   extern  "C"  fn  line_len(p1:  &Point,  p2:  &Point)  -­‐>  f64  {      /*  impl  */   }

Slide 43

Slide 43 text

Mapping typedef  void*  Poing;   typedef  double  f64;   /**      line_len  takes  two  Point  structs.  You  can  rely  on  the  fact  that  it        will  not  create  aliases  to  the  Points  that  outlive  the  invocation.      Point  should  be  memory  that  is  valid  and  immutable  for  the  duration      of  the  call  to  the  line_len  function.   */   f64  line_len(const  Point  p1,  const  Point  p2); #[no_mangle]   extern  "C"  fn  line_len(p1:  &Point,  p2:  &Point)  -­‐>  f64  {      /*  impl  */   }

Slide 44

Slide 44 text

Mapping typedef  void*  Poing;   typedef  double  f64;   /**      line_len  takes  two  Point  structs.  You  can  rely  on  the  fact  that  it        will  not  create  aliases  to  the  Points  that  outlive  the  invocation.      Point  should  be  memory  that  is  valid  and  immutable  for  the  duration      of  the  call  to  the  line_len  function.   */   f64  line_len(const  Point  p1,  const  Point  p2); #[no_mangle]   extern  "C"  fn  line_len(p1:  &Point,  p2:  &Point)  -­‐>  f64  {      /*  impl  */   }

Slide 45

Slide 45 text

Mapping typedef  void*  Poing;   typedef  double  f64;   /**      line_len  takes  two  Point  structs.  You  can  rely  on  the  fact  that  it        will  not  create  aliases  to  the  Points  that  outlive  the  invocation.      Point  should  be  memory  that  is  valid  and  immutable  for  the  duration      of  the  call  to  the  line_len  function.   */   f64  line_len(const  Point  p1,  const  Point  p2); #[no_mangle]   extern  "C"  fn  line_len(p1:  &Point,  p2:  &Point)  -­‐>  f64  {      /*  impl  */   }

Slide 46

Slide 46 text

Rust is a DSL for describing ownership concepts that you have to think about when writing C or C++

Slide 47

Slide 47 text

Step 3.
 Decide how to express and "enforce" the requirements from C

Slide 48

Slide 48 text

#include  ;   typedef  void*  Point;   typedef  double  f64;   int  main()  {      Cell  p1  =  NEW_CELL(new_point(10,  20));      Cell  p2  =  NEW_CELL(new_point(30,  10));      printf("%f",  length(p1,  p2));   }   double  length(Cell  c1,  Cell  c2)  {      Point  p1  =  BORROW(c1);      Point  p2  =  BORROW(c2);      return  line_len(p1,  p2);   }

Slide 49

Slide 49 text

#include  ;   typedef  void*  Point;   typedef  double  f64;   int  main()  {      Cell  c  =  NEW_CELL(new_point(10,  20));      Point  p1  =  TRANSFER(c);      print_and_dispose(p1);      Point  p2  =  BORROW(c);   }

Slide 50

Slide 50 text

#include  ;   typedef  void*  Point;   typedef  double  f64;   int  main()  {      Cell  c  =  NEW_CELL(new_point(10,  20));      Point  p1  =  TRANSFER(c);      print_and_dispose(p1);      Point  p2  =  BORROW(c);   } DYNAMIC  ERROR

Slide 51

Slide 51 text

Not Covered / My Opinions • Non-Simple return types (out-pointer + error boolean) • Non-opaque Rust structures in C (mostly YAGNI) • Dynamic ownership implementation (embedding-specific) • Catching panics (catch_panic coming soon!) • Paranoid extern functions (a different programming pattern)

Slide 52

Slide 52 text

Thanks! @wycats