Expand description
Error handling: turning igraph error codes into Rust Results.
The C library reports failures by returning an igraph_error_t code and
by invoking a (thread-local) error handler. The default handler aborts
the whole process, which is hardly what a Rust program wants. The first time
a thread calls into this crate, ensure_init installs a handler that
records the error message (so that it can be reported in an Error) and
then frees the current level of igraph’s internal cleanup (“finally”)
stack, exactly like igraph_error_handler_ignore does; the failing
function then returns its error code, which check converts into an
Error.
Warnings emitted by igraph are collected in a thread-local buffer as well;
retrieve them with take_warnings.
Rust callbacks invoked by igraph must never unwind into C: trampolines run
them inside catch_panic (or catch_panic_or), which stores the
panic and returns an error code to igraph; the wrapper’s check then
resumes the panic in Rust, after igraph has cleaned up.
§Threads
The crate requires igraph to be built in thread-safe mode (the
IGRAPH_THREAD_SAFE macro of igraph_threading.h must be 1, which is
checked at compile time): every thread then has its own igraph state,
namely error and warning handlers, “finally” stack (the list of
temporary objects to free if the running function fails) and default
random number generator. ensure_init sets them up the first time a
thread calls into the crate, so igraph can be used from many threads at
once. Nothing is shared between threads except what the user shares:
a Graph is Send but not Sync, and seeding the
random number generator (see rng) affects the calling
thread only.
§Callbacks that call igraph
A Rust closure invoked by a running igraph function (a visitor, a clique or motif handler, …) may itself call igraph functions, for instance to run a nested search. Two consequences of igraph’s per-thread “finally” stack are handled here:
catch_panicandcatch_panic_orrun the closure in a fresh level of the finally stack (IGRAPH_FINALLY_ENTER/IGRAPH_FINALLY_EXIT), so an igraph call that fails inside the closure frees only its own temporaries, never those of the outer function that is still running; the closure receives an ordinaryErrand may ignore it.- The finally stack holds at most 100 entries per thread, and igraph
aborts the process when it overflows. Each nested call adds its own
entries on top of the outer ones, so
igraph_call!(andGraph::init_with) refuse to start a C call when the stack already holds more thanMAX_NESTED_FINALLY_ENTRIESentries, returning anErrorKind::Failureerror (“igraph calls nested too deeply”) instead; in practice this allows a dozen or more levels of nested searches.
C (igraph_error.h) | Rust |
|---|---|
igraph_error_t return codes | Result, Error, ErrorKind (ErrorKind::from_raw, ErrorKind::to_raw) |
igraph_strerror | strerror, ErrorKind::description, Display |
igraph_set_error_handler, igraph_set_warning_handler, igraph_setup | ensure_init (automatic), is_initialized |
IGRAPH_CHECK | igraph_call!, check |
warnings (IGRAPH_WARNING) | take_warnings |
callbacks returning IGRAPH_INTERRUPTED | catch_panic, catch_panic_or, resume_panic, has_pending_panic |
IGRAPH_FINALLY_ENTER, IGRAPH_FINALLY_EXIT, IGRAPH_FINALLY_STACK_SIZE | used by catch_panic, catch_panic_or and igraph_call!; finally_stack_size |
Not wrapped: the error and warning reporting functions (igraph_error,
igraph_errorf, igraph_errorvf, igraph_warning, igraph_warningf,
igraph_fatal, igraph_fatalf) are meant for C code that raises igraph
errors, while Rust code returns an Error (see Error::new).
igraph_set_fatal_handler is deliberately left alone: a fatal handler
must not return, and a Rust function cannot unwind through the C frames
above it, so igraph’s default handler, which aborts the process, stays in
place. Fatal errors signal broken internal invariants (e.g. a corrupt
finally stack), not ordinary failures.
See also misc::set_progress_handler,
misc::set_status_handler and
misc::set_interruption_handler
for igraph’s other (progress, status and interruption) handlers.
§Example
use igraph::prelude::*;
let mut g = Graph::new(3, false);
// Vertex 7 does not exist: igraph reports an "invalid vertex id" error.
let err = g.add_edge(0, 7).unwrap_err();
assert_eq!(err.kind(), ErrorKind::InvalidVertexId);
assert!(!err.message().is_empty());
// The error names the C source location that raised it.
assert!(err.file().ends_with(".c") && err.line() > 0);
// Errors compose with `?` and `std::error::Error`.
fn degree_of_7(g: &Graph) -> Result<i64> {
g.degree_of(7, NeighborMode::All, Loops::Twice)
}
let boxed: Box<dyn std::error::Error> = degree_of_7(&g).unwrap_err().into();
assert!(boxed.to_string().starts_with(&ErrorKind::InvalidVertexId.description()));Structs§
- Error
- An error reported by the igraph C library, or raised by a wrapper that validated its arguments on the Rust side.
Enums§
- Error
Kind - The kind of an igraph error, mirroring the C enumeration
igraph_error_type_t.
Constants§
- MAX_
NESTED_ FINALLY_ ENTRIES - The number of entries of igraph’s (per-thread) finally stack above which
igraph_call!andGraph::init_withrefuse to start a C call, see the module docs.
Functions§
- catch_
panic - Runs a Rust closure invoked from C (a callback), catching panics so that they never unwind across the FFI boundary.
- catch_
panic_ or - Like
catch_panic, for callbacks whose C signature returns a value other than an error code (e.g. a boolean):on_panicis returned to C. - check
- Converts a raw igraph return code into a
Result, attaching the message recorded by the error handler:IGRAPH_SUCCESSgivesOk(()), any other code anErrorof the correspondingErrorKind. - ensure_
init - Initializes igraph for the calling thread, once.
- finally_
stack_ size - The current number of entries of igraph’s finally stack on the calling
thread (
IGRAPH_FINALLY_STACK_SIZE, undocumented inigraph_error.h). - has_
pending_ panic - Whether a panic caught by
catch_panicis waiting to be resumed on the calling thread (by the nextcheckorresume_panic). - is_
initialized - Whether
ensure_initalready ran on the calling thread. - resume_
panic - Resumes a panic caught by
catch_panicon this thread, if any. - strerror
- igraph’s textual description of a raw error code
(
igraph_strerror). - take_
warnings - Drains and returns the warnings that igraph emitted on the calling thread
(as
"<message> (<file>:<line>)"), oldest first.