#[cfg(ruby_lt_3_3)]
use rb_sys::rb_io_enc_t as rb_io_encoding;
#[cfg(ruby_gt_3_4)]
use rb_sys::rb_io_mode;
#[cfg(ruby_gte_3_3)]
use rb_sys::{rb_io_encoding, FMODE_EXTERNAL};
use rb_sys::{
rb_io_extract_modeenc, OnigEncodingTypeST, FMODE_APPEND, FMODE_BINMODE, FMODE_CREATE,
FMODE_DUPLEX, FMODE_EXCL, FMODE_READABLE, FMODE_READWRITE, FMODE_SETENC_BY_BOM, FMODE_SYNC,
FMODE_TEXTMODE, FMODE_TRUNC, FMODE_TTY, FMODE_WRITABLE, VALUE,
};
use crate::{
encoding::{Encoding, RbEncoding},
error::{protect, Error},
value::{private::ReprValue as _, ReprValue, Value},
RHash, Ruby,
};
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct OpenFlags(pub i32);
impl OpenFlags {
pub fn new(bits: i32) -> Self {
Self(bits)
}
pub fn bits(&self) -> i32 {
self.0
}
pub fn contains(&self, flag: i32) -> bool {
self.0 & flag != 0
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct FMode(u32);
#[cfg(ruby_lt_3_3)]
const FMODE_EXTERNAL: u32 = 65536;
impl FMode {
pub const READ: u32 = FMODE_READABLE;
pub const WRITE: u32 = FMODE_WRITABLE;
pub const READ_WRITE: u32 = FMODE_READWRITE;
pub const BINARY_MODE: u32 = FMODE_BINMODE;
pub const SYNC: u32 = FMODE_SYNC;
pub const TTY: u32 = FMODE_TTY;
pub const DUPLEX: u32 = FMODE_DUPLEX;
pub const APPEND: u32 = FMODE_APPEND;
pub const CREATE: u32 = FMODE_CREATE;
pub const EXCLUSIVE: u32 = FMODE_EXCL;
pub const TRUNCATE: u32 = FMODE_TRUNC;
pub const TEXT_MODE: u32 = FMODE_TEXTMODE;
pub const EXTERNAL_ENCODING: u32 = FMODE_EXTERNAL;
pub const BOM_ENCODING: u32 = FMODE_SETENC_BY_BOM;
pub fn new(bits: u32) -> Self {
Self(bits)
}
pub fn contains(&self, flag: u32) -> bool {
self.0 & flag != 0
}
pub fn bits(&self) -> u32 {
self.0
}
}
pub struct IoEncoding {
pub external: Option<Encoding>,
pub internal: Option<Encoding>,
pub flags: i32,
pub options: Option<RHash>,
}
impl Ruby {
pub fn io_extract_modeenc(
&self,
mode: &mut Value,
permission: &mut Value,
option: &RHash,
) -> Result<(OpenFlags, FMode, IoEncoding), Error> {
let mut oflags: std::os::raw::c_int = 0; #[cfg(ruby_lte_3_4)]
let mut fmode: std::os::raw::c_int = 0; #[cfg(ruby_gt_3_4)]
let mut fmode: rb_io_mode = rb_io_mode::RUBY_IO_MODE_EXTERNAL; let mut io_encoding: rb_io_encoding = unsafe { std::mem::zeroed() };
protect(|| unsafe {
rb_io_extract_modeenc(
&mut mode.as_rb_value() as *mut _,
&mut permission.as_rb_value() as *mut _,
option.as_rb_value(),
&mut oflags as *mut _,
&mut fmode as *mut _,
&mut io_encoding as *mut _,
);
self.qnil()
})?;
let open_flags = OpenFlags::new(oflags as i32);
let fmode_flags = FMode::new(fmode as u32);
let internal: Option<Encoding> = {
let ptr = io_encoding.enc as *mut OnigEncodingTypeST;
RbEncoding::new(ptr).map(|r| r.into())
};
let external: Option<Encoding> = {
let ptr = io_encoding.enc2 as *mut OnigEncodingTypeST;
RbEncoding::new(ptr).map(|r| r.into())
};
let flags = io_encoding.ecflags;
let options = {
let value = Value::new(io_encoding.ecopts as VALUE);
if value.is_nil() {
None
} else {
RHash::from_value(value)
}
};
let io_encoding = IoEncoding {
external,
internal,
flags,
options,
};
Ok((open_flags, fmode_flags, io_encoding))
}
}