Library API Design, First Layer
In C library APIs, one pointer can mean many different things:
int parse_packet(const uint8_t *data, size_t len, struct Packet *out);
void normalize(uint8_t *data, size_t len);
void consume_buffer(uint8_t *data, size_t len);
uint8_t *make_packet(size_t *out_len);
These signatures all involve pointers, but the API meaning differs:
- read-only input
- in-place mutation
- output result
- taking over a caller-owned resource
- creating a new resource for the caller
The first layer of Rust API design is making those intentions visible in the type.
Read-Only Input: Borrow
C read-only buffer:
uint32_t checksum(const uint8_t *data, size_t len);
Rust uses a slice:
fn checksum(data: &[u8]) -> u32 {
data.iter().map(|b| *b as u32).sum()
}
&[u8] means the function temporarily reads bytes. It does not own the memory and cannot mutate it.