use std::{fmt, io};
use crate::{
object::NonNullObject,
prelude::*,
};
#[derive(Clone, Copy, Debug)]
#[repr(transparent)]
pub struct InstrSeq(NonNullObject);
impl AsRef<AnyObject> for InstrSeq {
#[inline]
fn as_ref(&self) -> &AnyObject { self.0.as_ref() }
}
impl From<InstrSeq> for AnyObject {
#[inline]
fn from(obj: InstrSeq) -> Self { obj.0.into() }
}
impl PartialEq<AnyObject> for InstrSeq {
#[inline]
fn eq(&self, obj: &AnyObject) -> bool {
self.as_any_object() == obj
}
}
unsafe impl Object for InstrSeq {
#[inline]
fn unique_id() -> Option<u128> {
Some((!0) - 1)
}
#[inline]
fn cast<A: Object>(obj: A) -> Option<Self> {
if obj.class().inherits(Class::of::<Self>()) {
unsafe { Some(Self::cast_unchecked(obj)) }
} else {
None
}
}
}
impl fmt::Display for InstrSeq {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
self.as_any_object().fmt(f)
}
}
impl InstrSeq {
#[inline]
fn _compile(args: &[AnyObject]) -> Result<Self> {
unsafe {
Class::instr_seq()
.call_with_protected("compile", args)
.map(|obj| Self::cast_unchecked(obj))
}
}
#[inline]
pub fn compile(script: impl Into<String>) -> Result<Self> {
Self::_compile(&[script.into().into()])
}
#[inline]
pub fn compile_with(
script: impl Into<String>,
options: impl Into<Hash>,
) -> Result<Self> {
Self::_compile(&[script.into().into(), options.into().into()])
}
#[inline]
fn _compile_file(args: &[AnyObject]) -> Result<Self> {
unsafe {
Class::instr_seq()
.call_with_protected("compile_file", args)
.map(|obj| Self::cast_unchecked(obj))
}
}
#[inline]
pub fn compile_file(path: impl Into<String>) -> Result<Self> {
Self::_compile_file(&[path.into().into()])
}
#[inline]
pub fn compile_file_with(
path: impl Into<String>,
options: impl Into<Hash>,
) -> Result<Self> {
Self::_compile_file(&[path.into().into(), options.into().into()])
}
#[inline]
pub unsafe fn from_binary(binary: impl Into<String>) -> Self {
Self::cast_unchecked(Class::instr_seq().call_with(
"load_from_binary",
&[binary.into()]
))
}
#[inline]
pub unsafe fn eval(self) -> AnyObject {
self.call("eval")
}
#[inline]
pub fn eval_protected(self) -> Result<AnyObject> {
unsafe { self.call_protected("eval") }
}
#[inline]
pub fn to_binary(self) -> String {
unsafe { String::cast_unchecked(self.call("to_binary")) }
}
#[inline]
pub fn write_binary(self, mut w: impl io::Write) -> io::Result<()> {
let binary = self.to_binary();
let bytes = unsafe { binary.as_bytes() };
w.write_all(bytes)
}
#[inline]
pub fn disassemble(self) -> String {
unsafe { String::cast_unchecked(self.call("disasm")) }
}
#[inline]
pub fn path(self) -> String {
unsafe { String::cast_unchecked(self.call("path")) }
}
#[inline]
pub fn absolute_path(self) -> Option<String> {
unsafe {
let path = self.call("absolute_path");
if path.is_nil() {
None
} else {
Some(String::cast_unchecked(path))
}
}
}
}