use crate::{
containers::{List, Ptr, SharedList, StringPtr},
debug_level,
source::{CustomDecoder, CustomDecoderResult},
token_rewriter::{TokenRewriter, TokenRewriterResult},
ParserOptions, Token,
};
use std::ffi::c_void;
type ForeignCustomDecoderFn =
extern "C" fn(StringPtr, List<u8>, *mut c_void) -> CustomDecoderResult;
extern "C" fn dummy_decode(
_encoding: StringPtr,
input: List<u8>,
_state: *mut c_void,
) -> CustomDecoderResult {
CustomDecoderResult::Ok(input)
}
#[repr(C)]
#[derive(Debug)]
pub struct ForeignCustomDecoder {
pub f: ForeignCustomDecoderFn,
pub dummy: bool,
pub state: *mut c_void,
}
impl ForeignCustomDecoder {
pub fn new(f: ForeignCustomDecoderFn) -> Self {
Self {
f,
dummy: false,
state: std::ptr::null_mut(),
}
}
fn none() -> Self {
Self {
f: dummy_decode,
dummy: true,
state: std::ptr::null_mut(),
}
}
fn call(&self, encoding: StringPtr, input: List<u8>) -> CustomDecoderResult {
if self.dummy {
panic!("Can't run dummy decoder")
} else {
let f = self.f;
f(encoding, input, self.state)
}
}
}
type ForeignTokenRewriterFn =
extern "C" fn(Ptr<Token>, SharedList<u8>, *mut c_void) -> TokenRewriterResult;
extern "C" fn dummy_rewrite(
_token: Ptr<Token>,
_input: SharedList<u8>,
_state: *mut c_void,
) -> TokenRewriterResult {
unreachable!()
}
#[repr(C)]
#[derive(Debug)]
pub struct ForeignTokenRewriter {
pub f: ForeignTokenRewriterFn,
pub dummy: bool,
pub state: *mut c_void,
}
impl ForeignTokenRewriter {
pub fn new(f: ForeignTokenRewriterFn) -> Self {
Self {
f,
dummy: false,
state: std::ptr::null_mut(),
}
}
fn none() -> Self {
Self {
f: dummy_rewrite,
dummy: true,
state: std::ptr::null_mut(),
}
}
fn call(&self, token: Ptr<Token>, input: SharedList<u8>) -> TokenRewriterResult {
if self.dummy {
panic!("Can't run dummy token rewriter")
} else {
let f = self.f;
f(token, input, self.state)
}
}
}
#[repr(C)]
#[derive(Debug)]
pub struct ForeignParserOptions {
pub buffer_name: StringPtr,
pub debug: debug_level::Type,
pub decoder: ForeignCustomDecoder,
pub token_rewriter: ForeignTokenRewriter,
pub record_tokens: bool,
}
impl Default for ForeignParserOptions {
fn default() -> Self {
Self {
buffer_name: StringPtr::from("(eval)"),
debug: debug_level::NONE,
decoder: ForeignCustomDecoder::none(),
token_rewriter: ForeignTokenRewriter::none(),
record_tokens: true,
}
}
}
impl From<ForeignParserOptions> for ParserOptions {
fn from(options: ForeignParserOptions) -> Self {
let ForeignParserOptions {
buffer_name,
debug,
decoder,
token_rewriter,
record_tokens,
} = options;
let decoder = if decoder.dummy {
CustomDecoder::none()
} else {
CustomDecoder::new(Box::new(move |encoding: StringPtr, input: List<u8>| {
decoder.call(encoding, input)
}))
};
let token_rewriter = if token_rewriter.dummy {
TokenRewriter::none()
} else {
TokenRewriter::new(Box::new(move |token: Ptr<Token>, input: SharedList<u8>| {
token_rewriter.call(token, input)
}))
};
ParserOptions {
buffer_name: String::from(buffer_name),
debug,
decoder,
token_rewriter,
record_tokens,
}
}
}