Wrapping abs(3)

fn abs(x: i32) -> i32;

fn main() {
    let x = -42;
    let abs_x = abs(x);
    println!("{x}, {abs_x}");
}
This slide should take about 15 minutes.

In this slide, we’re establishing a pattern for writing wrappers.

Find the external definition of a function’s signature Write a matching function in Rust within an extern block Confirm which safety invariants need to be upheld Decide whether it’s possible to mark the function as safe

Note that this doesn’t work yet.

Add the extern block:

#![allow(unused)]
fn main() {
unsafe extern "C" {
    fn abs(x: i32) -> i32;
}
}

Explain that many POSIX functions are available in Rust because Cargo links against the C standard library (libc) by default, which brings its symbols into the program’s scope.

Show man 3 abs in the terminal or a webpage.

Explain that our function signature must match its definition: int abs(int j);.

Update the code block to use the C types.

#![allow(unused)]
fn main() {
use std::ffi::c_int;

unsafe extern "C" {
    fn abs(x: c_int) -> c_int;
}
}

Discuss rationale: using ffi::c_int increases the portability of our code. When the standard library is compiled for the target platform, the platform can determine the widths. According to the C standard, a c_int may be defined as an i16 rather than the much more common i32.

(Optional) Show the documentation for c_int to reveal that it is a type alias for i32.

Attempt to compile to trigger “error: extern blocks must be unsafe” error message.

Add the unsafe keyword to the block:

#![allow(unused)]
fn main() {
use std::ffi::c_int;

unsafe extern "C" {
    fn abs(x: c_int) -> c_int;
}
}

Check that learners understand the significance of this change. We are required to uphold type safety and other safety preconditions.

Recompile.

Add safe keyword to the abs function:

#![allow(unused)]
fn main() {
use std::ffi::c_int;

unsafe extern "C" {
    safe fn abs(x: c_int) -> c_int;
}
}

Explain that the safe fn marks abs as safe to call without an unsafe block.

Completed program for reference:

use std::ffi::c_int;

unsafe extern "C" {
    safe fn abs(x: c_int) -> c_int;
}

fn main() {
    let x = -42;
    let abs_x = abs(x);
    println!("{x}, {abs_x}");
}