Modèle d’erreurs (AirStatus)
Air rend ses erreurs in-band : la valeur de retour porte le statut. Pas
d’errno, pas d’exception, aucune panic qui traverse l’ABI. Cette page
explique comment tester, lire et propager ces statuts — et pourquoi
ce modèle a été choisi (ADR-045).
La règle de base
Presque toute fonction rend un enum AirStatus. AIR_STATUS_OK == 0 est le seul
cas de succès, et le seul cas où un *out est écrit :
AirUuid u;
AirStatus st = air_uuid_new_v7(&u);
if (st != AIR_STATUS_OK) {
/* `u` n'a PAS été écrit — ne pas le lire. */
fprintf(stderr, "échec : %s\n", air_status_message(st));
return 1;
}
/* Ici seulement, `u` est valide. */
Piège. Ne lisez jamais un paramètre de sortie avant d’avoir vérifié
AIR_STATUS_OK. Sur erreur,*outest laissé intact (non initialisé si vous ne l’aviez pas initialisé). C’est volontaire : zéro écriture partielle.
Lire un statut : air_status_message
const char *msg = air_status_message(st); /* jamais NULL */
La chaîne est statique (strerror-like, sans locale ni état global) : valide
pour toute la durée du programme, à ne pas libérer. C’est un message technique
en anglais, destiné aux logs/diagnostics — pas un texte localisé pour l’utilisateur
final.
Le catalogue des statuts
Deux familles, aux discriminants committés (ADR-012) :
| Plage | Origine | Exemples |
|---|---|---|
0 | succès | AIR_STATUS_OK |
1..=13 | miroir de AirErrorKind (couche 1) | AIR_STATUS_NOT_FOUND, AIR_STATUS_INVALID_DATA, AIR_STATUS_IO… |
100, 101 | propres à la frontière C | AIR_STATUS_NULL_ARGUMENT, AIR_STATUS_BUFFER_TOO_SMALL |
Les deux statuts de frontière sont ceux que vous pouvez déclencher par un mauvais usage de l’API :
AIR_STATUS_NULL_ARGUMENT(100) — un pointeur requis valaitNULL. Détecté par validation amont, sans déréférencement : passerNULLne provoque jamais de segfault côté Air, juste ce statut. (Les fonctions de libérationair_log_close/air_log_fields_freefont exception :NULLy est un no-op documenté, pas une erreur.)AIR_STATUS_BUFFER_TOO_SMALL(101) — votre buffer de sortie est trop petit. Rien n’est écrit (pas de troncature silencieuse, ADR-032). Agrandissez le buffer aux constantes du header et rappelez.
Pourquoi pas d’errno ?
errno est un état global par thread, fragile : facile à écraser entre l’appel
et sa lecture, invisible dans la signature, source de bugs classiques en C. Le statut
in-band est au contraire :
- explicite dans le type de retour (impossible de l’ignorer par mégarde) ;
- local (aucun état partagé, donc trivialement thread-safe) ;
- stable (discriminants committés).
Pourquoi aucune panic ne traverse l’ABI
La crate est compilée en panic = "abort". Conséquence : une panic Rust ne se
propage pas à travers la frontière C (ce serait un comportement indéfini) — elle
avorte le processus immédiatement (fail-fast). Autrement dit :
- une
panic= un bug dans Air, jamais une condition d’erreur normale ; - les conditions attendues (entrée invalide, ressource absente, buffer court) sont
toutes rendues via
AirStatus, jamais parpanic; - vous n’avez aucun
catchà écrire côté C, et aucunAIR_PANICà gérer : le contrat est « soitAirStatus, soit le processus s’arrête ».
C’est un choix de sûreté : mieux vaut un abort net et diagnosticable qu’un déroulement de pile qui corromprait l’état d’un appelant C.
Propager proprement
Comme AirStatus est une valeur, la propagation est triviale : relayez le statut, ou
mappez-le sur votre propre modèle d’erreurs. Schéma typique :
AirStatus do_work(AirLog *log) {
AirInstant t0;
AirStatus st = air_instant_now(&t0);
if (st != AIR_STATUS_OK) {
return st; /* remonte tel quel */
}
/* … */
return AIR_STATUS_OK;
}
English version: Error model.