#![allow(clippy::missing_safety_doc)]
use std::borrow::Cow;
use std::cell::RefCell;
use crate::{FormatParser, ParseEvent, ParseEventKind, ScalarValue};
use facet_core::Shape;
use super::jit_debug;
thread_local! {
static PENDING_FIELD_NAME: RefCell<Option<(*mut u8, usize, usize)>> = const { RefCell::new(None) };
}
#[repr(C)]
#[derive(Copy, Clone)]
pub struct RawEvent {
pub tag: EventTag,
pub scalar_tag: ScalarTag,
pub payload: EventPayload,
}
#[repr(u8)]
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum EventTag {
StructStart = 0,
StructEnd = 1,
ArrayStart = 2,
ArrayEnd = 3,
FieldKey = 4,
Scalar = 5,
OrderedField = 6,
Eof = 7,
Error = 255,
}
#[repr(C)]
#[derive(Copy, Clone)]
pub union EventPayload {
pub field_name: FieldNamePayload,
pub scalar: ScalarPayload,
pub error_code: i32,
pub empty: (),
}
#[repr(C)]
#[derive(Clone, Copy)]
pub struct FieldNamePayload {
pub ptr: *const u8,
pub len: usize,
}
#[repr(C)]
#[derive(Clone, Copy)]
pub union ScalarPayload {
pub bool_val: bool,
pub char_val: char,
pub i64_val: i64,
pub u64_val: u64,
pub i128_val: i128,
pub u128_val: u128,
pub f64_val: f64,
pub string_val: StringPayload,
pub is_null: bool,
}
#[repr(C)]
#[derive(Clone, Copy)]
pub struct StringPayload {
pub ptr: *const u8,
pub len: usize,
pub capacity: usize,
pub owned: bool,
}
fn string_into_raw_parts(s: String) -> (*mut u8, usize, usize) {
let mut s = std::mem::ManuallyDrop::new(s);
(s.as_mut_ptr(), s.len(), s.capacity())
}
fn vec_into_raw_parts(v: Vec<u8>) -> (*mut u8, usize, usize) {
let mut v = std::mem::ManuallyDrop::new(v);
(v.as_mut_ptr(), v.len(), v.capacity())
}
#[repr(u8)]
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum ScalarTag {
None = 0,
Null = 1,
Bool = 2,
I64 = 3,
U64 = 4,
F64 = 5,
Str = 6,
Bytes = 7,
I128 = 8,
U128 = 9,
Char = 10,
Unit = 11,
}
impl ScalarTag {
pub const fn from_u8(v: u8) -> Self {
match v {
0 => ScalarTag::None,
1 => ScalarTag::Null,
2 => ScalarTag::Bool,
3 => ScalarTag::I64,
4 => ScalarTag::U64,
5 => ScalarTag::F64,
6 => ScalarTag::Str,
7 => ScalarTag::Bytes,
8 => ScalarTag::I128,
9 => ScalarTag::U128,
10 => ScalarTag::Char,
11 => ScalarTag::Unit,
_ => ScalarTag::None,
}
}
}
pub const OK: i32 = 0;
#[allow(dead_code)]
pub const ERR_EXPECTED_STRUCT: i32 = -1;
#[allow(dead_code)]
pub const ERR_EXPECTED_FIELD_OR_END: i32 = -2;
#[allow(dead_code)]
pub const ERR_EXPECTED_SCALAR: i32 = -3;
pub const ERR_PARSER: i32 = -4;
pub const ERR_EXPECTED_ARRAY: i32 = -10;
pub const ERR_MISSING_REQUIRED_FIELD: i32 = -300;
pub const ERR_LIST_NOT_LIST_TYPE: i32 = -200;
pub const ERR_LIST_NO_INIT_FN: i32 = -201;
pub const ERR_LIST_NO_PUSH_FN: i32 = -202;
pub const ERR_LIST_UNSUPPORTED_SCALAR: i32 = -203;
pub const ERR_SCALAR_TYPE_MISMATCH: i32 = -206;
pub const ERR_LIST_UNSUPPORTED_ELEMENT: i32 = -204;
pub const ERR_LIST_UNSIZED_ELEMENT: i32 = -205;
pub const ERR_INVALID_OPTION_DISCRIMINANT: i32 = -301;
#[repr(C)]
pub struct ParserVTable {
pub next_event: unsafe extern "C" fn(*mut (), *mut RawEvent) -> i32,
pub skip_value: unsafe extern "C" fn(*mut ()) -> i32,
}
pub fn make_vtable<'de, P: FormatParser<'de>>() -> ParserVTable {
ParserVTable {
next_event: next_event_wrapper::<P>,
skip_value: skip_value_wrapper::<P>,
}
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn jit_peek_event(ctx: *mut JitContext, out: *mut RawEvent) -> i32 {
let ctx = unsafe { &mut *ctx };
if let Some(peeked) = ctx.peeked_event {
unsafe { *out = peeked };
return OK;
}
let result = unsafe { jit_next_event(ctx, out) };
if result == OK {
ctx.peeked_event = Some(unsafe { *out });
}
result
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn jit_next_event(ctx: *mut JitContext, out: *mut RawEvent) -> i32 {
let ctx_ref = unsafe { &mut *ctx };
if let Some(peeked) = ctx_ref.peeked_event.take() {
unsafe { *out = peeked };
return OK;
}
let vtable = unsafe { &*ctx_ref.vtable };
let next_event_fn = vtable.next_event;
unsafe { next_event_fn(ctx_ref.parser, out) }
}
unsafe extern "C" fn next_event_wrapper<'de, P: FormatParser<'de>>(
parser: *mut (),
out: *mut RawEvent,
) -> i32 {
PENDING_FIELD_NAME.with(|cell| {
if let Some((ptr, len, cap)) = cell.borrow_mut().take() {
unsafe {
let _ = String::from_raw_parts(ptr, len, cap);
}
}
});
let parser = unsafe { &mut *(parser as *mut P) };
match parser.next_event() {
Ok(Some(event)) => {
let raw = convert_event_to_raw(event);
if super::jit_debug_enabled() {
if raw.tag == EventTag::Scalar && raw.scalar_tag == ScalarTag::I64 {
jit_debug!(
"next_event: Scalar(I64({})) -> writing to {:p}",
unsafe { raw.payload.scalar.i64_val },
out
);
} else if raw.tag == EventTag::Scalar && raw.scalar_tag == ScalarTag::Str {
let payload = unsafe { raw.payload.scalar.string_val };
let s = unsafe {
std::str::from_utf8_unchecked(std::slice::from_raw_parts(
payload.ptr,
payload.len,
))
};
jit_debug!("next_event: Scalar(Str(\"{}\")) -> writing to {:p}", s, out);
} else {
jit_debug!("next_event: tag={:?}", raw.tag);
}
}
unsafe { *out = raw };
OK
}
Ok(None) => {
unsafe {
*out = RawEvent {
tag: EventTag::Eof,
scalar_tag: ScalarTag::None,
payload: EventPayload { error_code: 0 },
};
}
OK
}
Err(_) => {
unsafe {
*out = RawEvent {
tag: EventTag::Error,
scalar_tag: ScalarTag::None,
payload: EventPayload {
error_code: ERR_PARSER,
},
};
}
ERR_PARSER
}
}
}
unsafe extern "C" fn skip_value_wrapper<'de, P: FormatParser<'de>>(parser: *mut ()) -> i32 {
let parser = unsafe { &mut *(parser as *mut P) };
match parser.skip_value() {
Ok(()) => OK,
Err(_) => ERR_PARSER,
}
}
#[repr(C)]
pub struct JitContext {
pub parser: *mut (),
pub vtable: *const ParserVTable,
pub peeked_event: Option<RawEvent>,
pub fields_seen: u64,
}
pub const JIT_CONTEXT_FIELDS_SEEN_OFFSET: usize = std::mem::offset_of!(JitContext, fields_seen);
fn convert_event_to_raw(event: ParseEvent<'_>) -> RawEvent {
match event.kind {
ParseEventKind::StructStart(_) => RawEvent {
tag: EventTag::StructStart,
scalar_tag: ScalarTag::None,
payload: EventPayload { empty: () },
},
ParseEventKind::StructEnd => RawEvent {
tag: EventTag::StructEnd,
scalar_tag: ScalarTag::None,
payload: EventPayload { empty: () },
},
ParseEventKind::SequenceStart(_) => RawEvent {
tag: EventTag::ArrayStart,
scalar_tag: ScalarTag::None,
payload: EventPayload { empty: () },
},
ParseEventKind::SequenceEnd => RawEvent {
tag: EventTag::ArrayEnd,
scalar_tag: ScalarTag::None,
payload: EventPayload { empty: () },
},
ParseEventKind::VariantTag(_) => RawEvent {
tag: EventTag::Error,
scalar_tag: ScalarTag::None,
payload: EventPayload { error_code: -2 },
},
ParseEventKind::FieldKey(key) => {
let (ptr, len) = match key.name() {
Some(Cow::Borrowed(s)) => (s.as_ptr(), s.len()),
Some(Cow::Owned(s)) => {
let s = s.clone();
let (ptr, len, cap) = string_into_raw_parts(s);
PENDING_FIELD_NAME.with(|cell| {
*cell.borrow_mut() = Some((ptr, len, cap));
});
(ptr as *const u8, len)
}
None => {
("".as_ptr(), 0)
}
};
RawEvent {
tag: EventTag::FieldKey,
scalar_tag: ScalarTag::None,
payload: EventPayload {
field_name: FieldNamePayload { ptr, len },
},
}
}
ParseEventKind::OrderedField => RawEvent {
tag: EventTag::OrderedField,
scalar_tag: ScalarTag::None,
payload: EventPayload { empty: () },
},
ParseEventKind::Scalar(scalar) => {
let (scalar_tag, payload) = match scalar {
ScalarValue::Null => (
ScalarTag::Null,
EventPayload {
scalar: ScalarPayload { is_null: true },
},
),
ScalarValue::Bool(b) => (
ScalarTag::Bool,
EventPayload {
scalar: ScalarPayload { bool_val: b },
},
),
ScalarValue::Char(c) => (
ScalarTag::Char,
EventPayload {
scalar: ScalarPayload { char_val: c },
},
),
ScalarValue::I64(n) => (
ScalarTag::I64,
EventPayload {
scalar: ScalarPayload { i64_val: n },
},
),
ScalarValue::U64(n) => (
ScalarTag::U64,
EventPayload {
scalar: ScalarPayload { u64_val: n },
},
),
ScalarValue::F64(n) => (
ScalarTag::F64,
EventPayload {
scalar: ScalarPayload { f64_val: n },
},
),
ScalarValue::Str(s) => {
let (ptr, len, capacity, owned) = match s {
Cow::Borrowed(s) => (s.as_ptr(), s.len(), 0, false),
Cow::Owned(s) => {
let (ptr, len, cap) = string_into_raw_parts(s);
(ptr as *const u8, len, cap, true)
}
};
(
ScalarTag::Str,
EventPayload {
scalar: ScalarPayload {
string_val: StringPayload {
ptr,
len,
capacity,
owned,
},
},
},
)
}
ScalarValue::Bytes(b) => {
let (ptr, len, capacity, owned) = match b {
Cow::Borrowed(b) => (b.as_ptr(), b.len(), 0, false),
Cow::Owned(b) => {
let (ptr, len, cap) = vec_into_raw_parts(b);
(ptr as *const u8, len, cap, true)
}
};
(
ScalarTag::Bytes,
EventPayload {
scalar: ScalarPayload {
string_val: StringPayload {
ptr,
len,
capacity,
owned,
},
},
},
)
}
ScalarValue::I128(n) => (
ScalarTag::I128,
EventPayload {
scalar: ScalarPayload { i128_val: n },
},
),
ScalarValue::U128(n) => (
ScalarTag::U128,
EventPayload {
scalar: ScalarPayload { u128_val: n },
},
),
ScalarValue::Unit => (
ScalarTag::Unit,
EventPayload {
scalar: ScalarPayload { is_null: true },
},
),
};
RawEvent {
tag: EventTag::Scalar,
scalar_tag,
payload,
}
}
}
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn jit_write_u8(out: *mut u8, offset: usize, value: u8) {
unsafe {
*out.add(offset) = value;
}
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn jit_write_u16(out: *mut u8, offset: usize, value: u16) {
unsafe {
let ptr = out.add(offset) as *mut u16;
*ptr = value;
}
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn jit_write_u32(out: *mut u8, offset: usize, value: u32) {
unsafe {
let ptr = out.add(offset) as *mut u32;
*ptr = value;
}
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn jit_write_u64(out: *mut u8, offset: usize, value: u64) {
jit_debug!("write_u64: value={} to {:p}+{}", value, out, offset);
unsafe {
let ptr = out.add(offset) as *mut u64;
std::ptr::write_unaligned(ptr, value);
}
}
#[unsafe(no_mangle)]
pub const unsafe extern "C" fn jit_write_i8(out: *mut u8, offset: usize, value: i8) {
unsafe {
let ptr = out.add(offset) as *mut i8;
std::ptr::write_unaligned(ptr, value);
}
}
#[unsafe(no_mangle)]
pub const unsafe extern "C" fn jit_write_i16(out: *mut u8, offset: usize, value: i16) {
unsafe {
let ptr = out.add(offset) as *mut i16;
std::ptr::write_unaligned(ptr, value);
}
}
#[unsafe(no_mangle)]
pub const unsafe extern "C" fn jit_write_i32(out: *mut u8, offset: usize, value: i32) {
unsafe {
let ptr = out.add(offset) as *mut i32;
std::ptr::write_unaligned(ptr, value);
}
}
#[unsafe(no_mangle)]
pub const unsafe extern "C" fn jit_write_i64(out: *mut u8, offset: usize, value: i64) {
unsafe {
let ptr = out.add(offset) as *mut i64;
std::ptr::write_unaligned(ptr, value);
}
}
#[unsafe(no_mangle)]
pub const unsafe extern "C" fn jit_write_f32(out: *mut u8, offset: usize, value: f32) {
unsafe {
let ptr = out.add(offset) as *mut f32;
std::ptr::write_unaligned(ptr, value);
}
}
#[unsafe(no_mangle)]
pub const unsafe extern "C" fn jit_write_f64(out: *mut u8, offset: usize, value: f64) {
unsafe {
let ptr = out.add(offset) as *mut f64;
std::ptr::write_unaligned(ptr, value);
}
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn jit_write_bool(out: *mut u8, offset: usize, value: bool) {
unsafe {
*out.add(offset) = value as u8;
}
}
#[cold]
#[inline(never)]
fn jit_write_string_debug_entry(
out: *mut u8,
offset: usize,
ptr: *const u8,
len: usize,
capacity: usize,
owned: bool,
) {
let slice = unsafe { std::slice::from_raw_parts(ptr, len) };
let s = std::str::from_utf8(slice).unwrap_or("<invalid utf8>");
let target = (out as usize + offset) as *const u8;
let preview: String = s.chars().take(50).collect();
jit_debug!(
"jit_write_string: out={:p}, offset={}, len={}, owned={}, cap={}, string=\"{}\"",
out,
offset,
len,
owned,
capacity,
preview
);
jit_debug!(" -> src_ptr={:p}, target={:p}", ptr, target);
if ptr.is_null() {
jit_debug!(" -> ERROR: Source pointer is NULL!");
} else if (ptr as usize) < 0x100000000 {
jit_debug!(
" -> WARNING: Source pointer 0x{:x} looks suspicious!",
ptr as usize
);
}
if owned && capacity < len {
jit_debug!(" -> ERROR: capacity ({}) < len ({})!", capacity, len);
}
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn jit_write_string(
out: *mut u8,
offset: usize,
ptr: *const u8,
len: usize,
capacity: usize,
owned: bool,
) {
if super::jit_debug_enabled() {
jit_write_string_debug_entry(out, offset, ptr, len, capacity, owned);
}
let string = if !owned {
let mut s = String::with_capacity(len);
unsafe {
std::ptr::copy_nonoverlapping(ptr, s.as_mut_ptr(), len);
s.as_mut_vec().set_len(len);
}
s
} else {
unsafe { String::from_raw_parts(ptr as *mut u8, len, capacity) }
};
unsafe {
std::ptr::write(out.add(offset) as *mut String, string);
}
}
#[unsafe(no_mangle)]
pub const unsafe extern "C" fn jit_memcpy(dest: *mut u8, src: *const u8, len: usize) {
unsafe {
std::ptr::copy(src, dest, len);
}
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn jit_write_error_string(
scratch: *mut u8,
msg_ptr: *const u8,
msg_len: usize,
) {
use crate::{DeserializeError, DeserializeErrorKind};
let msg_slice = unsafe { std::slice::from_raw_parts(msg_ptr, msg_len) };
let msg_str = std::str::from_utf8(msg_slice).unwrap_or("invalid utf8 in error message");
let error = DeserializeError {
span: None,
path: None,
kind: DeserializeErrorKind::Bug {
error: msg_str.to_owned().into(),
context: "JIT deserialization",
},
};
unsafe {
let scratch_typed = scratch as *mut DeserializeError;
std::ptr::write(scratch_typed, error);
}
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn jit_field_matches(
name_ptr: *const u8,
name_len: usize,
expected_ptr: *const u8,
expected_len: usize,
) -> i32 {
if name_len != expected_len {
jit_debug!(
"field_matches: len mismatch {} != {}",
name_len,
expected_len
);
return 0;
}
let name = unsafe { std::slice::from_raw_parts(name_ptr, name_len) };
let expected = unsafe { std::slice::from_raw_parts(expected_ptr, expected_len) };
let matches = if name == expected { 1 } else { 0 };
if super::jit_debug_enabled() {
let name_str = std::str::from_utf8(name).unwrap_or("<invalid>");
let expected_str = std::str::from_utf8(expected).unwrap_or("<invalid>");
jit_debug!(
"field_matches: '{}' == '{}' ? {}",
name_str,
expected_str,
matches
);
}
matches
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn jit_deserialize_nested(
ctx: *mut JitContext,
out: *mut u8,
func_ptr: *const u8,
) -> i32 {
jit_debug!(
"jit_deserialize_nested: out={:p}, func_ptr={:p}",
out,
func_ptr
);
if func_ptr.is_null() {
jit_debug!(" -> ERROR: func_ptr is NULL!");
panic!("Nested deserializer function pointer is NULL");
}
let addr = func_ptr as usize;
if addr < 0x100000000 {
jit_debug!(
" -> WARNING: func_ptr looks suspicious (too low): {:#x}",
addr
);
}
type NestedFn = unsafe extern "C" fn(*mut JitContext, *mut u8) -> i32;
let func: NestedFn = unsafe { std::mem::transmute(func_ptr) };
jit_debug!(" -> calling nested deserializer at {:p}", func_ptr);
let result = unsafe { func(ctx, out) };
jit_debug!(" -> nested deserializer returned: {}", result);
result
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn jit_option_init_none(out: *mut u8, init_none_fn: *const u8) {
type InitNoneFn = unsafe extern "C" fn(facet_core::PtrUninit) -> facet_core::PtrMut;
let func: InitNoneFn = unsafe { std::mem::transmute(init_none_fn) };
unsafe { func(facet_core::PtrUninit::new(out)) };
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn jit_option_init_some_from_value(
out: *mut u8,
value_ptr: *mut u8,
init_some_fn: *const u8,
) {
use facet_core::{PtrMut, PtrUninit};
type InitSomeFn = unsafe extern "C" fn(PtrUninit, PtrMut) -> facet_core::PtrMut;
let init_some: InitSomeFn = unsafe { std::mem::transmute(init_some_fn) };
unsafe { init_some(PtrUninit::new(out), PtrMut::new(value_ptr)) };
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn jit_result_init_ok_from_value(
out: *mut u8,
value_ptr: *mut u8,
init_ok_fn: *const u8,
) {
use facet_core::{PtrMut, PtrUninit};
type InitOkFn = unsafe extern "C" fn(PtrUninit, PtrMut) -> facet_core::PtrMut;
let init_ok: InitOkFn = unsafe { std::mem::transmute(init_ok_fn) };
unsafe { init_ok(PtrUninit::new(out), PtrMut::new(value_ptr)) };
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn jit_result_init_err_from_value(
out: *mut u8,
value_ptr: *mut u8,
init_err_fn: *const u8,
) {
use facet_core::{PtrMut, PtrUninit};
type InitErrFn = unsafe extern "C" fn(PtrUninit, PtrMut) -> facet_core::PtrMut;
let init_err: InitErrFn = unsafe { std::mem::transmute(init_err_fn) };
unsafe { init_err(PtrUninit::new(out), PtrMut::new(value_ptr)) };
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn jit_vec_init_with_capacity(
out: *mut u8,
capacity: usize,
init_fn: *const u8,
) {
use facet_core::{PtrMut, PtrUninit};
type InitFn = unsafe extern "C" fn(PtrUninit, usize) -> PtrMut;
let func: InitFn = unsafe { std::mem::transmute(init_fn) };
unsafe { func(PtrUninit::new(out), capacity) };
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn jit_map_init_with_capacity(
out: *mut u8,
capacity: usize,
init_fn: *const u8,
) {
use facet_core::{PtrMut, PtrUninit};
type InitFn = unsafe extern "C" fn(PtrUninit, usize) -> PtrMut;
let func: InitFn = unsafe { std::mem::transmute(init_fn) };
unsafe { func(PtrUninit::new(out), capacity) };
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn jit_drop_in_place(shape_ptr: *const u8, ptr: *mut u8) {
use facet_core::PtrMut;
let shape: &Shape = unsafe { &*(shape_ptr as *const Shape) };
unsafe { shape.call_drop_in_place(PtrMut::new(ptr)) };
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn jit_vec_push(
ctx: *mut JitContext,
vec_ptr: *mut u8,
push_fn: *const u8,
item_deserializer: *const u8,
) -> i32 {
let mut item_buf: [u8; 256] = [0; 256];
let item_ptr = item_buf.as_mut_ptr();
type DeserializeFn = unsafe extern "C" fn(*mut JitContext, *mut u8) -> i32;
let deserialize: DeserializeFn = unsafe { std::mem::transmute(item_deserializer) };
let result = unsafe { deserialize(ctx, item_ptr) };
if result != 0 {
return result;
}
type PushFn = unsafe extern "C" fn(facet_core::PtrMut, facet_core::PtrMut);
let push: PushFn = unsafe { std::mem::transmute(push_fn) };
unsafe {
push(
facet_core::PtrMut::new(vec_ptr),
facet_core::PtrMut::new(item_ptr),
)
};
0
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn jit_deserialize_vec(
ctx: *mut JitContext,
out: *mut u8,
init_fn: *const u8,
push_fn: *const u8,
elem_size: usize,
elem_deserializer: *const u8,
scalar_tag: u8, ) -> i32 {
let mut raw_event = RawEvent {
tag: EventTag::Error,
scalar_tag: ScalarTag::I64,
payload: EventPayload {
scalar: ScalarPayload { i64_val: 0 },
},
};
let ctx_ref = unsafe { &mut *ctx };
let vtable = unsafe { &*ctx_ref.vtable };
let result = unsafe { (vtable.next_event)(ctx_ref.parser, &mut raw_event) };
if result != 0 {
return result;
}
if raw_event.tag != EventTag::ArrayStart {
return ERR_EXPECTED_STRUCT; }
type InitFn = unsafe extern "C" fn(facet_core::PtrUninit, usize) -> facet_core::PtrMut;
let init: InitFn = unsafe { std::mem::transmute(init_fn) };
unsafe { init(facet_core::PtrUninit::new(out), 0) };
let mut elem_buf: [u8; 1024] = [0; 1024];
if elem_size > elem_buf.len() {
return -100;
}
loop {
let peeked = unsafe { jit_peek_event(ctx, &mut raw_event) };
if peeked != 0 {
return peeked;
}
if raw_event.tag == EventTag::ArrayEnd {
let result = unsafe { (vtable.next_event)(ctx_ref.parser, &mut raw_event) };
if result != 0 {
return result;
}
break;
}
let elem_ptr = elem_buf.as_mut_ptr();
if !elem_deserializer.is_null() {
type DeserializeFn = unsafe extern "C" fn(*mut JitContext, *mut u8) -> i32;
let deserialize: DeserializeFn = unsafe { std::mem::transmute(elem_deserializer) };
let result = unsafe { deserialize(ctx, elem_ptr) };
if result != 0 {
return result;
}
} else {
let result = unsafe { (vtable.next_event)(ctx_ref.parser, &mut raw_event) };
if result != 0 {
return result;
}
if raw_event.tag != EventTag::Scalar {
return ERR_EXPECTED_SCALAR;
}
let scalar_tag_expected = ScalarTag::from_u8(scalar_tag);
let tag_valid = match scalar_tag_expected {
ScalarTag::I64 | ScalarTag::U64 | ScalarTag::F64 => {
raw_event.scalar_tag == ScalarTag::I64
|| raw_event.scalar_tag == ScalarTag::U64
|| raw_event.scalar_tag == ScalarTag::F64
}
_ => raw_event.scalar_tag == scalar_tag_expected,
};
if !tag_valid {
return ERR_SCALAR_TYPE_MISMATCH;
}
match scalar_tag_expected {
ScalarTag::I64 => {
let val = unsafe { raw_event.payload.scalar.i64_val };
unsafe { *(elem_ptr as *mut i64) = val };
}
ScalarTag::U64 => {
let val = unsafe { raw_event.payload.scalar.u64_val };
unsafe { *(elem_ptr as *mut u64) = val };
}
ScalarTag::F64 => {
let val = unsafe { raw_event.payload.scalar.f64_val };
unsafe { *(elem_ptr as *mut f64) = val };
}
ScalarTag::Bool => {
let val = unsafe { raw_event.payload.scalar.bool_val };
unsafe { *(elem_ptr as *mut bool) = val };
}
_ => {
return -101;
}
}
}
type PushFn = unsafe extern "C" fn(facet_core::PtrMut, facet_core::PtrMut);
let push: PushFn = unsafe { std::mem::transmute(push_fn) };
unsafe {
push(
facet_core::PtrMut::new(out),
facet_core::PtrMut::new(elem_ptr),
)
};
}
OK
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn jit_vec_push_bool(vec_ptr: *mut u8, push_fn: *const u8, value: bool) {
let mut val = value;
let val_ptr = &mut val as *mut bool as *mut u8;
type PushFn = unsafe extern "C" fn(facet_core::PtrMut, facet_core::PtrMut);
let push: PushFn = unsafe { std::mem::transmute(push_fn) };
unsafe {
push(
facet_core::PtrMut::new(vec_ptr),
facet_core::PtrMut::new(val_ptr),
)
};
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn jit_vec_push_u8(vec_ptr: *mut u8, push_fn: *const u8, value: u8) {
let mut val = value;
let val_ptr = &mut val as *mut u8;
type PushFn = unsafe extern "C" fn(facet_core::PtrMut, facet_core::PtrMut);
let push: PushFn = unsafe { std::mem::transmute(push_fn) };
unsafe {
push(
facet_core::PtrMut::new(vec_ptr),
facet_core::PtrMut::new(val_ptr),
)
};
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn jit_vec_push_i64(vec_ptr: *mut u8, push_fn: *const u8, value: i64) {
let mut val = value;
let val_ptr = &mut val as *mut i64 as *mut u8;
type PushFn = unsafe extern "C" fn(facet_core::PtrMut, facet_core::PtrMut);
let push: PushFn = unsafe { std::mem::transmute(push_fn) };
unsafe {
push(
facet_core::PtrMut::new(vec_ptr),
facet_core::PtrMut::new(val_ptr),
)
};
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn jit_vec_push_u64(vec_ptr: *mut u8, push_fn: *const u8, value: u64) {
let mut val = value;
let val_ptr = &mut val as *mut u64 as *mut u8;
type PushFn = unsafe extern "C" fn(facet_core::PtrMut, facet_core::PtrMut);
let push: PushFn = unsafe { std::mem::transmute(push_fn) };
unsafe {
push(
facet_core::PtrMut::new(vec_ptr),
facet_core::PtrMut::new(val_ptr),
)
};
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn jit_vec_push_f64(vec_ptr: *mut u8, push_fn: *const u8, value: f64) {
let mut val = value;
let val_ptr = &mut val as *mut f64 as *mut u8;
type PushFn = unsafe extern "C" fn(facet_core::PtrMut, facet_core::PtrMut);
let push: PushFn = unsafe { std::mem::transmute(push_fn) };
unsafe {
push(
facet_core::PtrMut::new(vec_ptr),
facet_core::PtrMut::new(val_ptr),
)
};
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn jit_drop_owned_string(ptr: *mut u8, len: usize, cap: usize) {
unsafe {
drop(String::from_raw_parts(ptr, len, cap));
}
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn jit_vec_push_string(
vec_ptr: *mut u8,
push_fn: *const u8,
ptr: *const u8,
len: usize,
capacity: usize,
owned: bool,
) {
let string = if owned {
unsafe { String::from_raw_parts(ptr as *mut u8, len, capacity) }
} else {
let slice = unsafe { std::slice::from_raw_parts(ptr, len) };
std::str::from_utf8(slice).unwrap_or("").to_string()
};
let mut val = string;
let val_ptr = &mut val as *mut String as *mut u8;
type PushFn = unsafe extern "C" fn(facet_core::PtrMut, facet_core::PtrMut);
let push: PushFn = unsafe { std::mem::transmute(push_fn) };
unsafe {
push(
facet_core::PtrMut::new(vec_ptr),
facet_core::PtrMut::new(val_ptr),
)
};
std::mem::forget(val);
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn jit_vec_set_len(vec_ptr: *mut u8, len: usize, set_len_fn: *const u8) {
use facet_core::PtrMut;
type SetLenFn = unsafe extern "C" fn(PtrMut, usize);
let func: SetLenFn = unsafe { std::mem::transmute(set_len_fn) };
unsafe { func(PtrMut::new(vec_ptr), len) };
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn jit_vec_as_mut_ptr_typed(
vec_ptr: *mut u8,
as_mut_ptr_typed_fn: *const u8,
) -> *mut u8 {
use facet_core::PtrMut;
type AsMutPtrTypedFn = unsafe extern "C" fn(PtrMut) -> *mut u8;
let func: AsMutPtrTypedFn = unsafe { std::mem::transmute(as_mut_ptr_typed_fn) };
unsafe { func(PtrMut::new(vec_ptr)) }
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn jit_vec_reserve(
vec_ptr: *mut u8,
additional: usize,
reserve_fn: *const u8,
) {
use facet_core::PtrMut;
type ReserveFn = unsafe extern "C" fn(PtrMut, usize);
let func: ReserveFn = unsafe { std::mem::transmute(reserve_fn) };
unsafe { func(PtrMut::new(vec_ptr), additional) };
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn jit_vec_capacity(vec_ptr: *const u8, capacity_fn: *const u8) -> usize {
use facet_core::PtrConst;
type CapacityFn = unsafe extern "C" fn(PtrConst) -> usize;
let func: CapacityFn = unsafe { std::mem::transmute(capacity_fn) };
unsafe { func(PtrConst::new(vec_ptr)) }
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn jit_deserialize_list_by_shape(
ctx: *mut JitContext,
out: *mut u8,
list_shape: *const Shape,
elem_struct_deserializer: *const u8,
) -> i32 {
use facet_core::{Def, ScalarType};
let shape = unsafe { &*list_shape };
jit_debug!("jit_deserialize_list_by_shape: type={shape}");
let Def::List(list_def) = &shape.def else {
jit_debug!(
"ERROR: not a list type, def={:?}",
std::mem::discriminant(&shape.def)
);
return ERR_LIST_NOT_LIST_TYPE;
};
let elem_shape = list_def.t;
let elem_size = elem_shape
.layout
.sized_layout()
.map(|l| l.size())
.unwrap_or(0);
jit_debug!("list element: type={elem_shape}, size={elem_size}");
if elem_size == 0 {
jit_debug!("ERROR: unsized element type");
return ERR_LIST_UNSIZED_ELEMENT;
}
let Some(init_fn) = list_def.init_in_place_with_capacity() else {
jit_debug!("ERROR: no init function for list");
return ERR_LIST_NO_INIT_FN;
};
let Some(push_fn) = list_def.push() else {
jit_debug!("ERROR: no push function for list");
return ERR_LIST_NO_PUSH_FN;
};
let mut raw_event = RawEvent {
tag: EventTag::Error,
scalar_tag: ScalarTag::None,
payload: EventPayload {
scalar: ScalarPayload { i64_val: 0 },
},
};
let result = unsafe { jit_next_event(ctx, &mut raw_event) };
if result != 0 {
jit_debug!(
"ERROR: failed to read ArrayStart, parser returned {}",
result
);
return result;
}
if raw_event.tag != EventTag::ArrayStart {
jit_debug!("ERROR: expected ArrayStart, got {:?}", raw_event.tag);
return ERR_EXPECTED_ARRAY;
}
jit_debug!("list: got ArrayStart, initializing Vec");
let out_uninit = facet_core::PtrUninit::new(out);
unsafe { init_fn(out_uninit, 0) };
let out_mut = facet_core::PtrMut::new(out);
let elem_buf: Vec<u8> = vec![0u8; elem_size];
let elem_ptr = elem_buf.as_ptr() as *mut u8;
let elem_scalar_type = elem_shape.scalar_type();
let elem_is_list = matches!(&elem_shape.def, Def::List(_));
let elem_is_struct = matches!(
&elem_shape.ty,
facet_core::Type::User(facet_core::UserType::Struct(_))
);
jit_debug!(
"list element classification: is_scalar={}, is_list={}, is_struct={}, has_deserializer={}",
elem_scalar_type.is_some(),
elem_is_list,
elem_is_struct,
!elem_struct_deserializer.is_null()
);
jit_debug!(
"elem_buf address: {:p}, elem_ptr: {:p}",
elem_buf.as_ptr(),
elem_ptr
);
loop {
let peeked = unsafe { jit_peek_event(ctx, &mut raw_event) };
if peeked != 0 {
return peeked;
}
if raw_event.tag == EventTag::ArrayEnd {
let result = unsafe { jit_next_event(ctx, &mut raw_event) };
if result != 0 {
return result;
}
break;
}
unsafe { std::ptr::write_bytes(elem_ptr, 0, elem_size) };
if elem_is_list {
let result = unsafe {
jit_deserialize_list_by_shape(
ctx,
elem_ptr,
elem_shape as *const Shape,
std::ptr::null(),
)
};
if result != 0 {
jit_debug!(
"ERROR: nested list deserialization failed with code {}",
result
);
return result;
}
} else if elem_is_struct && !elem_struct_deserializer.is_null() {
type DeserializeFn = unsafe extern "C" fn(*mut JitContext, *mut u8) -> i32;
let deserialize: DeserializeFn =
unsafe { std::mem::transmute(elem_struct_deserializer) };
jit_debug!(
"deserializing struct element using compiled deserializer at elem_ptr={:p}",
elem_ptr
);
let result = unsafe { deserialize(ctx, elem_ptr) };
if result != 0 {
jit_debug!(
"ERROR: struct element deserialization failed with code {}",
result
);
return result;
}
} else if let Some(scalar_type) = elem_scalar_type {
let result = unsafe { jit_next_event(ctx, &mut raw_event) };
if result != 0 {
return result;
}
if raw_event.tag != EventTag::Scalar {
return ERR_EXPECTED_SCALAR;
}
let tag_valid = match scalar_type {
ScalarType::I8
| ScalarType::I16
| ScalarType::I32
| ScalarType::I64
| ScalarType::U8
| ScalarType::U16
| ScalarType::U32
| ScalarType::U64
| ScalarType::F32
| ScalarType::F64 => {
raw_event.scalar_tag == ScalarTag::I64
|| raw_event.scalar_tag == ScalarTag::U64
|| raw_event.scalar_tag == ScalarTag::F64
}
ScalarType::Bool => raw_event.scalar_tag == ScalarTag::Bool,
ScalarType::String => raw_event.scalar_tag == ScalarTag::Str,
_ => true, };
if !tag_valid {
return ERR_SCALAR_TYPE_MISMATCH;
}
match scalar_type {
ScalarType::I8 => {
let val = unsafe { raw_event.payload.scalar.i64_val } as i8;
unsafe { *(elem_ptr as *mut i8) = val };
}
ScalarType::I16 => {
let val = unsafe { raw_event.payload.scalar.i64_val } as i16;
unsafe { *(elem_ptr as *mut i16) = val };
}
ScalarType::I32 => {
let val = unsafe { raw_event.payload.scalar.i64_val } as i32;
unsafe { *(elem_ptr as *mut i32) = val };
}
ScalarType::I64 => {
let val = unsafe { raw_event.payload.scalar.i64_val };
unsafe { *(elem_ptr as *mut i64) = val };
}
ScalarType::U8 => {
let val = unsafe { raw_event.payload.scalar.u64_val } as u8;
unsafe { *elem_ptr = val };
}
ScalarType::U16 => {
let val = unsafe { raw_event.payload.scalar.u64_val } as u16;
unsafe { *(elem_ptr as *mut u16) = val };
}
ScalarType::U32 => {
let val = unsafe { raw_event.payload.scalar.u64_val } as u32;
unsafe { *(elem_ptr as *mut u32) = val };
}
ScalarType::U64 => {
let val = unsafe { raw_event.payload.scalar.u64_val };
unsafe { *(elem_ptr as *mut u64) = val };
}
ScalarType::F32 => {
let val = unsafe { raw_event.payload.scalar.f64_val } as f32;
unsafe { *(elem_ptr as *mut f32) = val };
}
ScalarType::F64 => {
let val = unsafe { raw_event.payload.scalar.f64_val };
unsafe { *(elem_ptr as *mut f64) = val };
}
ScalarType::Bool => {
let val = unsafe { raw_event.payload.scalar.bool_val };
unsafe { *(elem_ptr as *mut bool) = val };
}
ScalarType::String => {
let string_payload = unsafe { raw_event.payload.scalar.string_val };
let s = if string_payload.owned {
unsafe {
String::from_raw_parts(
string_payload.ptr as *mut u8,
string_payload.len,
string_payload.capacity,
)
}
} else {
let slice = unsafe {
std::slice::from_raw_parts(string_payload.ptr, string_payload.len)
};
std::str::from_utf8(slice).unwrap_or("").to_string()
};
unsafe { std::ptr::write(elem_ptr as *mut String, s) };
}
_ => {
jit_debug!(
"ERROR: unsupported scalar type {:?} in list element",
scalar_type
);
return ERR_LIST_UNSUPPORTED_SCALAR;
}
}
} else {
jit_debug!(
"ERROR: unsupported element type in list: {}",
elem_shape.type_identifier
);
return ERR_LIST_UNSUPPORTED_ELEMENT;
}
let elem_ptr = facet_core::PtrMut::new(elem_ptr);
unsafe { push_fn(out_mut, elem_ptr) };
}
jit_debug!("list deserialization complete");
OK
}
pub const RAW_EVENT_SIZE: usize = std::mem::size_of::<RawEvent>();
pub const RAW_EVENT_TAG_OFFSET: usize = 0;
pub const RAW_EVENT_PAYLOAD_OFFSET: usize = std::mem::offset_of!(RawEvent, payload);
pub const JIT_CONTEXT_PARSER_OFFSET: usize = std::mem::offset_of!(JitContext, parser);
pub const JIT_CONTEXT_VTABLE_OFFSET: usize = std::mem::offset_of!(JitContext, vtable);
pub const VTABLE_SKIP_VALUE_OFFSET: usize = std::mem::offset_of!(ParserVTable, skip_value);
pub const FIELD_NAME_PTR_OFFSET: usize = std::mem::offset_of!(FieldNamePayload, ptr);
pub const FIELD_NAME_LEN_OFFSET: usize = std::mem::offset_of!(FieldNamePayload, len);
pub const RAW_EVENT_SCALAR_TAG_OFFSET: usize = std::mem::offset_of!(RawEvent, scalar_tag);
pub const SCALAR_VALUE_OFFSET: usize = 0;
pub const STRING_PTR_OFFSET: usize = std::mem::offset_of!(StringPayload, ptr);
pub const STRING_LEN_OFFSET: usize = std::mem::offset_of!(StringPayload, len);
pub const STRING_CAPACITY_OFFSET: usize = std::mem::offset_of!(StringPayload, capacity);
pub const STRING_OWNED_OFFSET: usize = std::mem::offset_of!(StringPayload, owned);
#[repr(C)]
pub struct MapCollector {
buffer: Vec<u8>,
count: usize,
pair_stride: usize,
value_offset: usize,
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn jit_map_collector_new(
pair_stride: usize,
value_offset: usize,
) -> *mut MapCollector {
let collector = Box::new(MapCollector {
buffer: Vec::new(),
count: 0,
pair_stride,
value_offset,
});
Box::into_raw(collector)
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn jit_map_collector_push(
collector: *mut MapCollector,
key_ptr: *const u8,
key_len: usize,
key_cap: usize,
key_owned: u8,
value_ptr: *const u8,
value_size: usize,
) {
let collector = unsafe { &mut *collector };
let key: String = if key_owned != 0 {
unsafe { String::from_raw_parts(key_ptr as *mut u8, key_len, key_cap) }
} else {
let slice = unsafe { std::slice::from_raw_parts(key_ptr, key_len) };
unsafe { std::str::from_utf8_unchecked(slice) }.to_owned()
};
let pair_offset = collector.count * collector.pair_stride;
let new_size = pair_offset + collector.pair_stride;
if collector.buffer.len() < new_size {
collector.buffer.resize(new_size, 0);
}
let key_dst = unsafe { collector.buffer.as_mut_ptr().add(pair_offset) as *mut String };
unsafe { std::ptr::write(key_dst, key) };
let value_dst = unsafe {
collector
.buffer
.as_mut_ptr()
.add(pair_offset + collector.value_offset)
};
unsafe { std::ptr::copy_nonoverlapping(value_ptr, value_dst, value_size) };
collector.count += 1;
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn jit_map_collector_finalize(
collector: *mut MapCollector,
out_ptr: *mut u8,
from_pair_slice_fn: *const u8,
) {
use facet_core::PtrUninit;
let mut collector = unsafe { Box::from_raw(collector) };
let count = collector.count;
type FromPairSliceFn = unsafe extern "C" fn(PtrUninit, *mut u8, usize) -> facet_core::PtrMut;
let from_pair_slice: FromPairSliceFn = unsafe { std::mem::transmute(from_pair_slice_fn) };
unsafe {
from_pair_slice(
PtrUninit::new(out_ptr),
collector.buffer.as_mut_ptr(),
count,
)
};
unsafe { collector.buffer.set_len(0) };
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn jit_map_collector_abort(collector: *mut MapCollector) {
let collector = unsafe { Box::from_raw(collector) };
for i in 0..collector.count {
let pair_offset = i * collector.pair_stride;
let key_ptr = unsafe { collector.buffer.as_ptr().add(pair_offset) as *mut String };
unsafe { std::ptr::drop_in_place(key_ptr) };
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_memory_layout() {
eprintln!("RawEvent size: {}", std::mem::size_of::<RawEvent>());
eprintln!("RawEvent align: {}", std::mem::align_of::<RawEvent>());
eprintln!("EventPayload size: {}", std::mem::size_of::<EventPayload>());
eprintln!(
"ScalarPayload size: {}",
std::mem::size_of::<ScalarPayload>()
);
eprintln!(
"StringPayload size: {}",
std::mem::size_of::<StringPayload>()
);
eprintln!("RAW_EVENT_TAG_OFFSET: {}", RAW_EVENT_TAG_OFFSET);
eprintln!("RAW_EVENT_PAYLOAD_OFFSET: {}", RAW_EVENT_PAYLOAD_OFFSET);
let raw = RawEvent {
tag: EventTag::Scalar,
scalar_tag: ScalarTag::I64,
payload: EventPayload {
scalar: ScalarPayload { i64_val: 42 },
},
};
let ptr = &raw as *const RawEvent as *const u8;
unsafe {
let payload_ptr = ptr.add(RAW_EVENT_PAYLOAD_OFFSET);
let value = *(payload_ptr as *const i64);
eprintln!("Expected 42, got {}", value);
assert_eq!(value, 42, "i64 value should be at offset 0 of payload");
}
}
#[test]
fn test_string_payload_layout() {
assert_eq!(
std::mem::offset_of!(StringPayload, ptr),
0,
"ptr should be at offset 0"
);
assert_eq!(
std::mem::offset_of!(StringPayload, len),
8,
"len should be at offset 8"
);
assert_eq!(
std::mem::offset_of!(StringPayload, capacity),
16,
"capacity should be at offset 16"
);
assert_eq!(
std::mem::offset_of!(StringPayload, owned),
24,
"owned should be at offset 24"
);
eprintln!("StringPayload offsets verified:");
eprintln!(" ptr: {}", std::mem::offset_of!(StringPayload, ptr));
eprintln!(" len: {}", std::mem::offset_of!(StringPayload, len));
eprintln!(
" capacity: {}",
std::mem::offset_of!(StringPayload, capacity)
);
eprintln!(" owned: {}", std::mem::offset_of!(StringPayload, owned));
}
#[test]
fn test_string_into_raw_parts() {
let s = String::from("hello world");
let original_ptr = s.as_ptr();
let original_len = s.len();
let original_cap = s.capacity();
let (ptr, len, cap) = string_into_raw_parts(s);
assert_eq!(ptr as *const u8, original_ptr);
assert_eq!(len, original_len);
assert_eq!(cap, original_cap);
unsafe {
let _ = String::from_raw_parts(ptr, len, cap);
}
}
}