//! # Wrapping Terrible C++
//!
//! Suppose we're using the following terrible C++ library:
//! ```cpp
#![doc = include_str!("ircd.cpp")]
//! ```
//!
//! There's a lot wrong with this library. We'll ignore:
//! * Vague string encoding (ASCII? UTF8? Windows-1251? System Locale? Which one?)
//! * Potential for [static initialization order fiasco](https://en.cppreference.com/w/cpp/language/siof).
//! * [`std::bad_alloc` exceptions](https://en.cppreference.com/w/cpp/memory/new/bad_alloc) could cross FFI boundaries.
//! * Probably more I haven't bothered to list.
//!
//! However, if we can at least assume we're the only user of this library,
//! [Valrow]\[[Mut](ValrowMut)\]
and ZSTs can help us tackle *these* issues:
//! * Not reentrant (e.g. calling `add_user` from within `per_user` results in undefined behavior via invalidated iterators.)
//! Fixed by guarding global state with singleton ZSTs.
//!
//! * No thread safety (e.g. calling `add_user` from multiple threads is undefined behavior.)
//! Fixed by putting said singleton ZSTs within rust-owned [`Mutex`](std::sync::Mutex)es.
//!
//! * No context parameters for callbacks (no sane way to pass captured lambda state.)
//! Fixed by static asserting `FnMut()`s are ZSTs, which can still capture borrows via [Valrow]\[[Mut](ValrowMut)\]
.
//!
//!
//! # Demonstration
//! ```
#![doc = include_str!("ircd.rs")]
//! #
//! # mod cxx { // mimic ircd.cpp in raw Rust
//! # #![allow(non_upper_case_globals)]
//! # use abistr::*;
//! # use std::ffi::CString;
//! #
//! # static mut channels : Vec = Vec::new();
//! # static mut users : Vec = Vec::new();
//! #
//! # #[no_mangle] extern "C" fn add_channel (channel: CStrPtr ) { unsafe { channels.push(channel.to_cstr().into()) } }
//! # #[no_mangle] extern "C" fn add_user (user: CStrPtr ) { unsafe { users .push(user .to_cstr().into()) } }
//! # #[no_mangle] extern "C" fn for_each_channel (per_channel: extern "C" fn(CStrPtr) ) { unsafe { for channel in channels.iter() { per_channel((&**channel).into()) } } }
//! # #[no_mangle] extern "C" fn for_each_user (per_user: extern "C" fn(CStrPtr) ) { unsafe { for user in users .iter() { per_user( (&**user ).into()) } } }
//! # }
//! ```
use crate::*;