[![Crate](https://img.shields.io/crates/v/libnotcurses-sys.svg)](https://crates.io/crates/libnotcurses-sys)
[![API](https://docs.rs/libnotcurses-sys/badge.svg)](https://dankamongmen.github.io/notcurses/rustdoc/libnotcurses_sys/)
[![MSRV: 1.48.0](https://flat.badgen.net/badge/MSRV/1.48.0/purple)](https://blog.rust-lang.org/2020/11/19/Rust-1.48.html)

`libnotcurses-sys` is a low-level Rust wrapper for the
[notcurses C library](https://www.github.com/dankamongmen/notcurses/)

This library is built with several layers of zero-overhead abstractions
over the C functions and pointers accessed through FFI.

# How to use this library

There are basically two ways: The [**Rust way**](#1-the-rust-way),
and the [**C way**](#2-the-c-way). (Or a mix of both).

## 1. The Rust way

Where you use the more safely wrapped types, with its methods and constructors,
and painless error handling, like this:

```rust
use libnotcurses_sys::*;

fn main() -> NcResult<()> {
    let mut nc = Nc::with_flags(NCOPTION_NO_ALTERNATE_SCREEN)?;
    let plane = nc.stdplane();
    plane.putstr("hello world")?;
    nc.render()?;
    nc.stop()?;
    Ok(())
}
```

Although you still have to manually call the `stop()` method for `Nc`
and `NcDirect` objects, and the `destroy()` method for the rest of types that
allocate, (like `NcPlane`, `NcMenu`…) at the end of their scope, since the Drop
trait is not implemented for any wrapping type in libnotcurses-sys.

But they do implement methods and use `NcResult` as the return type,
for handling errors in the way we are used to in Rust.

For the types that don't allocate, most are based on primitives like `i32`,
`u32`, `u64`… without a name in the C library. In Rust they are type aliased
(e.g.: `NcChannel`, `NcChannelPair`, `NcRgb`, `NcColor`…), to
leverage type checking, and they implement methods through traits
(e.g. `NcChannelMethods` must be in scope to use the `NcChannel` methods.

## 2. The C way

You can always use the C API functions directly if you prefer,
in a very similar way as the C library is used.

It requires the use of unsafe, since most functions are wrapped directly
by `bindgen` marked as such.

Error handling is done this way by checking the returned `NcIntResult`,
or in case of receiving a pointer, by comparing it to `null_mut()`.

### Example

```rust
use core::ptr::{null, null_mut};
use std::process::exit;

use libnotcurses_sys::*;

fn main() {
    let options = ffi::notcurses_options {
        termtype: null(),
        loglevel: 0,
        margin_t: 0,
        margin_r: 0,
        margin_b: 0,
        margin_l: 0,
        flags: NCOPTION_NO_ALTERNATE_SCREEN,
    };
    unsafe {
        let nc = notcurses_init(&options, null_mut());
        if nc == null_mut() {
            exit(1);
        }
        let plane = notcurses_stdplane(nc);
        let cols = ncplane_putstr(&mut *plane, "hello world");
        if cols < NCRESULT_OK {
            notcurses_stop(nc);
            exit(cols.abs());
        }
        if notcurses_stop(nc) < NCRESULT_OK {
            exit(2);
        }
    }
}

```

### The `notcurses` C API docs

- [API reference (man pages)](https://notcurses.com/)
- [Wiki Page](https://nick-black.com/dankwiki/index.php/Notcurses)
- [The Book Guide (pdf)](https://nick-black.com/htp-notcurses.pdf)
- [USAGE.md](https://github.com/dankamongmen/notcurses/blob/master/USAGE.md)
- [HACKING.md](https://github.com/dankamongmen/notcurses/blob/master/doc/HACKING.md)
- [Doxygen Documentation](https://nick-black.com/notcurses/html/index.html)
- [FOSDEM 2021 presentation](https://fosdem.org/2021/schedule/event/notcurses/)

