libedit_sys/lib.rs
1#![allow(non_upper_case_globals)]
2#![allow(non_camel_case_types)]
3#![allow(non_snake_case)]
4#![allow(dead_code)]
5#![allow(unknown_lints)]
6#![allow(unnecessary_transmutes)]
7#![allow(clippy::all)]
8
9//! Low-level FFI bindings to the [libedit](https://www.thrysoee.dk/editline/)
10//! line-editing library (also known as editline, the BSD alternative to GNU
11//! readline).
12//!
13//! These are **raw, unsafe** bindings generated by bindgen. They provide
14//! direct access to the C API with no ergonomic wrappers.
15//!
16//! # Variadic functions
17//!
18//! Several core functions are C variadic (`el_set`, `el_get`, `el_wset`,
19//! `el_wget`, `history`, `history_w`). Calling C variadic functions from
20//! Rust is **undefined behavior** and may silently corrupt data.
21//!
22//! *Simple integer/pointer arguments often work by accident*, but this is
23//! not guaranteed across platforms or compiler versions. To safely use the
24//! full libedit API, you have two options:
25//!
26//! 1. Write a small C shim that wraps specific variadic call patterns
27//! with fixed-argument functions.
28//!
29//! 2. Use the companion [`libedit`](https://crates.io/crates/libedit)
30//! crate, which provides safe wrappers and includes the necessary C shim.
31//!
32//! This crate intentionally keeps the raw variadic bindings available so
33//! advanced users are not restricted, but they are **use at your own risk**.
34
35// When the `bindgen` feature is enabled, use freshly generated bindings.
36// Otherwise, use the pre-generated bindings shipped with the crate
37// (platform-specific: macOS ships an older libedit with fewer symbols).
38#[cfg(feature = "bindgen")]
39include!(concat!(env!("OUT_DIR"), "/bindings.rs"));
40
41#[cfg(all(not(feature = "bindgen"), target_os = "macos"))]
42include!("bindings-macos.rs");
43
44#[cfg(all(not(feature = "bindgen"), not(target_os = "macos")))]
45include!("bindings.rs");
46
47// Safety assertions at compile time
48#[cfg(test)]
49mod tests {
50 use super::*;
51 use std::mem;
52
53 #[test]
54 fn test_editline_type_sizes() {
55 // EditLine, History, and Tokenizer are opaque pointers -- verify they compile
56 assert_eq!(mem::size_of::<*const EditLine>(), mem::size_of::<usize>());
57 assert_eq!(mem::size_of::<*const History>(), mem::size_of::<usize>());
58 assert_eq!(mem::size_of::<*const Tokenizer>(), mem::size_of::<usize>());
59 }
60
61 #[test]
62 fn test_file_used_only_behind_pointer() {
63 // `FILE` is deliberately an opaque, zero-sized type: libedit and this
64 // crate only ever use it as `*mut FILE`. A pointer to it must be a
65 // single machine word regardless of what libc's real `FILE` size is
66 // on the target platform. This locks in the "only used behind a
67 // pointer" contract so a future change that relies on the pointee's
68 // size (which would be platform-specific and unsound) can't slip in
69 // unnoticed.
70 assert_eq!(mem::size_of::<*mut FILE>(), mem::size_of::<usize>());
71 assert_eq!(
72 mem::size_of::<FILE>(),
73 0,
74 "FILE must remain zero-sized/opaque"
75 );
76 }
77
78 #[test]
79 fn test_hist_event() {
80 // HistEvent is a concrete struct, verify it exists
81 let _event: HistEvent = unsafe { mem::zeroed() };
82 }
83}