The Rust binding is a safe wrapper over the same C ABI, with the unsafe FFI surface kept in one place rather than spread through your code.
let dongle = Dongle::open(None)?; // first dongle found
if !dongle.is_genuine() {
return Err(LicenseError::NotGenuine);
}
dongle.session_open()?;
let license: Vec<u8> = dongle.record_read("license")?;
// Drop closes the device -- including on the error paths above.Code language: Rust (rust)
Fallible calls return Result, so the error paths are the ones the compiler already makes you handle, and Drop closes the device without a cleanup path to forget.
One deliberate exception to the Result pattern
is_genuine returns a plain bool rather than Result<bool>: a licence gate should fail closed when no dongle is present, not force you to decide what an error means at every call site.
And the rule that matters in every language: do not branch on a boolean. Encrypt data your program genuinely needs with appEncrypt at build time and decrypt it through the dongle at run time, so removing the check leaves the program with nothing to compute rather than a working unlicensed copy.