rutie 0.10.0

The tie between Ruby and Rust.
Documentation
use crate::{
    binding::global::RubySpecialConsts,
    rubysys::{encoding, string, vm},
    types::{
        c_char, c_int, c_long, size_t, EncodingIndex, EncodingType, InternalValue, Value, ValueType,
    },
    util,
};
use std::ffi::CString;

pub fn default_external() -> Value {
    unsafe { encoding::rb_enc_default_external() }
}

pub fn default_internal() -> Value {
    unsafe { encoding::rb_enc_default_internal() }
}

pub fn force_encoding(s: Value, enc: Value) -> Value {
    unsafe { encoding::rb_enc_associate(s, encoding::rb_to_encoding(enc)) }
}

pub fn coderange_clear(obj: Value) {
    unsafe { encoding::coderange_clear(obj) }
}

// best str1/str2 encoding or nil if incompatible
pub fn compatible_encoding(str1: Value, str2: Value) -> Value {
    unsafe { encoding::rb_enc_from_encoding(encoding::rb_enc_compatible(str1, str2)) }
}

pub fn is_compatible_encoding(str1: Value, str2: Value) -> bool {
    compatible_encoding(str1, str2).ty() != ValueType::Nil
}

pub fn from_encoding_index(idx: EncodingIndex) -> Value {
    unsafe { encoding::rb_enc_from_encoding(encoding::rb_enc_from_index(idx)) }
}

pub fn usascii_encoding() -> Value {
    unsafe { from_encoding_index(encoding::rb_usascii_encindex()) }
}

pub fn utf8_encoding() -> Value {
    unsafe { from_encoding_index(encoding::rb_utf8_encindex()) }
}

pub fn enc_get_index(s: Value) -> EncodingIndex {
    let idx = unsafe { encoding::rb_enc_get_index(s) };

    idx
}

pub fn find_encoding_index(name: &str) -> EncodingIndex {
    let cstr = CString::new(name).unwrap();
    let idx = unsafe { encoding::rb_enc_find_index(cstr.as_ptr()) };

    idx
}

pub fn encode(str: Value, to: Value, ecflags: c_int, ecopts: Value) -> Value {
    unsafe { encoding::rb_str_encode(str, to, ecflags, ecopts) }
}

// Ruby writes the prepared options (what `rb_str_encode` expects as
// `ecopts`) through `opts`.
pub fn econv_prepare_opts(opthash: Value, opts: &mut Value) -> c_int {
    unsafe { encoding::rb_econv_prepare_opts(opthash, opts) }
}

// ptr - pointer for current point in string starting from the beginning
// end - pointer for the end of the string
// len_p - a mutable integer pointer for Ruby to give us how much we need to add on to `ptr`
// enc - the encoding the codepoints will be based on
pub fn next_codepoint(
    ptr: *const c_char,
    end: *const c_char,
    len_p: *mut c_int,
    enc: Value,
) -> usize {
    unsafe { encoding::rb_enc_codepoint_len(ptr, end, len_p, encoding::rb_to_encoding(enc)) }
}

pub fn ascii_8bit_encoding() -> Value {
    unsafe { encoding::rb_enc_from_encoding(encoding::rb_ascii8bit_encoding()) }
}

pub fn locale_encoding() -> Value {
    unsafe { encoding::rb_enc_from_encoding(encoding::rb_locale_encoding()) }
}

pub fn filesystem_encoding() -> Value {
    unsafe { encoding::rb_enc_from_encoding(encoding::rb_filesystem_encoding()) }
}

// The `Encoding` of `object`, or `nil` when it has none.
pub fn encoding_of(object: Value) -> Value {
    unsafe {
        let encoding = encoding::rb_enc_get(object);

        if encoding.is_null() {
            Value::from(RubySpecialConsts::Nil as InternalValue)
        } else {
            encoding::rb_enc_from_encoding(encoding)
        }
    }
}

pub fn encoding_index(enc: Value) -> EncodingIndex {
    unsafe { encoding::rb_to_encoding_index(enc) }
}

// Raises `RangeError` for a code point the encoding cannot represent.
pub fn chr(code: u32, enc: Value) -> Value {
    unsafe { encoding::rb_enc_uint_chr(code, encoding::rb_to_encoding(enc)) }
}

// Appends `bytes` (in `enc`) to `string`, converting as `String#<<` does;
// raises `Encoding::CompatibilityError` when they cannot be combined.
pub fn concat_bytes(string: Value, bytes: &[u8], enc: Value) -> Value {
    unsafe {
        encoding::rb_enc_str_buf_cat(
            string,
            bytes.as_ptr() as *const c_char,
            bytes.len() as c_long,
            encoding::rb_to_encoding(enc),
        )
    }
}