Skip to main content

Module error

Module error 

Source
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_panic and catch_panic_or run 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 ordinary Err and 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! (and Graph::init_with) refuse to start a C call when the stack already holds more than MAX_NESTED_FINALLY_ENTRIES entries, returning an ErrorKind::Failure error (“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 codesResult, Error, ErrorKind (ErrorKind::from_raw, ErrorKind::to_raw)
igraph_strerrorstrerror, ErrorKind::description, Display
igraph_set_error_handler, igraph_set_warning_handler, igraph_setupensure_init (automatic), is_initialized
IGRAPH_CHECKigraph_call!, check
warnings (IGRAPH_WARNING)take_warnings
callbacks returning IGRAPH_INTERRUPTEDcatch_panic, catch_panic_or, resume_panic, has_pending_panic
IGRAPH_FINALLY_ENTER, IGRAPH_FINALLY_EXIT, IGRAPH_FINALLY_STACK_SIZEused 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§

ErrorKind
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! and Graph::init_with refuse 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_panic is returned to C.
check
Converts a raw igraph return code into a Result, attaching the message recorded by the error handler: IGRAPH_SUCCESS gives Ok(()), any other code an Error of the corresponding ErrorKind.
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 in igraph_error.h).
has_pending_panic
Whether a panic caught by catch_panic is waiting to be resumed on the calling thread (by the next check or resume_panic).
is_initialized
Whether ensure_init already ran on the calling thread.
resume_panic
Resumes a panic caught by catch_panic on 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.

Type Aliases§

Result
Specialized Result type used throughout the crate.