#[doc(hidden)]
pub use serde_json;
use serde::{Deserialize, Serialize};
use std::collections::{BTreeMap, HashMap};
#[derive(Debug, Deserialize)]
pub struct FieldContext {
pub table_name: String,
pub field_name: String,
pub field_type: String,
pub record_index: usize,
pub total_records: usize,
pub record_id: String,
}
#[derive(Serialize)]
#[doc(hidden)]
pub struct __FieldOutput {
pub value: Option<String>,
pub error: Option<String>,
}
#[macro_export]
macro_rules! define_mock_data_plugin {
(|$ctx:ident : &FieldContext| $body:expr) => {
#[unsafe(no_mangle)]
pub extern "C" fn alloc(size: i32) -> i32 {
let layout = ::std::alloc::Layout::from_size_align(size as usize, 1).unwrap();
unsafe { ::std::alloc::alloc(layout) as i32 }
}
#[unsafe(no_mangle)]
pub extern "C" fn dealloc(ptr: i32, len: i32) {
let layout = ::std::alloc::Layout::from_size_align(len as usize, 1).unwrap();
unsafe { ::std::alloc::dealloc(ptr as *mut u8, layout) }
}
#[unsafe(no_mangle)]
pub extern "C" fn generate_field(ptr: i32, len: i32) -> i64 {
let input_bytes =
unsafe { ::std::slice::from_raw_parts(ptr as *const u8, len as usize) };
let output = match $crate::serde_json::from_slice::<$crate::FieldContext>(input_bytes) {
Ok($ctx) => {
let $ctx = &$ctx;
let result: Option<&str> = (|| $body)();
match result {
Some(val) => $crate::__FieldOutput {
value: Some(val.to_string()),
error: None,
},
None => $crate::__FieldOutput {
value: None,
error: Some("skip".into()),
},
}
}
Err(e) => $crate::__FieldOutput {
value: None,
error: Some(format!("parse error: {}", e)),
},
};
let bytes = $crate::serde_json::to_vec(&output).unwrap();
let out_ptr = alloc(bytes.len() as i32);
unsafe {
::std::ptr::copy_nonoverlapping(bytes.as_ptr(), out_ptr as *mut u8, bytes.len());
}
((out_ptr as i64) << 32) | (bytes.len() as i64)
}
};
}
#[derive(Debug, Deserialize)]
#[serde(tag = "kind")]
pub enum TypeContext {
Struct {
pipeline: String,
generator: String,
config: serde_json::Value,
},
Table {
pipeline: String,
generator: String,
struct_config: serde_json::Value,
table_config: serde_json::Value,
},
Enum {
pipeline: String,
generator: String,
config: serde_json::Value,
},
}
impl TypeContext {
pub fn pipeline(&self) -> &str {
match self {
TypeContext::Struct { pipeline, .. }
| TypeContext::Table { pipeline, .. }
| TypeContext::Enum { pipeline, .. } => pipeline,
}
}
pub fn generator(&self) -> &str {
match self {
TypeContext::Struct { generator, .. }
| TypeContext::Table { generator, .. }
| TypeContext::Enum { generator, .. } => generator,
}
}
pub fn type_name(&self) -> Option<&str> {
match self {
TypeContext::Struct { config, .. } => {
config.get("struct_name").and_then(|v| v.as_str())
}
TypeContext::Table { struct_config, .. } => {
struct_config.get("struct_name").and_then(|v| v.as_str())
}
TypeContext::Enum { config, .. } => config.get("enum_name").and_then(|v| v.as_str()),
}
}
pub fn table_name(&self) -> Option<&str> {
match self {
TypeContext::Table { table_config, .. } => {
table_config.get("table_name").and_then(|v| v.as_str())
}
_ => None,
}
}
pub fn is_relation(&self) -> bool {
match self {
TypeContext::Table { table_config, .. } => {
table_config.get("relation").is_some_and(|v| !v.is_null())
}
_ => false,
}
}
pub fn has_explicit_permissions(&self) -> bool {
match self {
TypeContext::Table { table_config, .. } => table_config
.get("permissions")
.is_some_and(|v| !v.is_null()),
_ => false,
}
}
pub fn has_explicit_events(&self) -> bool {
match self {
TypeContext::Table { table_config, .. } => table_config
.get("events")
.and_then(|v| v.as_array())
.is_some_and(|arr| !arr.is_empty()),
_ => false,
}
}
pub fn has_explicit_mock_data(&self) -> bool {
match self {
TypeContext::Table { table_config, .. } => table_config
.get("mock_generation_config")
.is_some_and(|v| !v.is_null()),
_ => false,
}
}
pub fn existing_macroforge_derives(&self) -> Vec<String> {
let node = match self {
TypeContext::Struct { config, .. } => config.get("macroforge_derives"),
TypeContext::Table { struct_config, .. } => struct_config.get("macroforge_derives"),
TypeContext::Enum { config, .. } => config.get("macroforge_derives"),
};
node.and_then(|v| v.as_array())
.map(|arr| {
arr.iter()
.filter_map(|v| v.as_str().map(str::to_string))
.collect()
})
.unwrap_or_default()
}
pub fn annotations(&self) -> Vec<String> {
let node = match self {
TypeContext::Struct { config, .. } => config.get("annotations"),
TypeContext::Table { struct_config, .. } => struct_config.get("annotations"),
TypeContext::Enum { config, .. } => config.get("annotations"),
};
node.and_then(|v| v.as_array())
.map(|arr| {
arr.iter()
.filter_map(|v| v.as_str().map(str::to_string))
.collect()
})
.unwrap_or_default()
}
pub fn raw_attributes(&self) -> BTreeMap<String, Vec<String>> {
let node = match self {
TypeContext::Struct { config, .. } => config.get("raw_attributes"),
TypeContext::Table { struct_config, .. } => struct_config.get("raw_attributes"),
TypeContext::Enum { config, .. } => config.get("raw_attributes"),
};
node.and_then(|v| v.as_object())
.map(|obj| {
obj.iter()
.filter_map(|(k, v)| {
let bodies: Vec<String> = v
.as_array()?
.iter()
.filter_map(|x| x.as_str().map(str::to_string))
.collect();
Some((k.clone(), bodies))
})
.collect()
})
.unwrap_or_default()
}
pub fn fields(&self) -> Vec<TypeFieldInfo> {
let arr = match self {
TypeContext::Struct { config, .. } => config.get("fields"),
TypeContext::Table { struct_config, .. } => struct_config.get("fields"),
TypeContext::Enum { config, .. } => config.get("variants"),
};
arr.and_then(|v| v.as_array())
.map(|items| {
items
.iter()
.map(|v| TypeFieldInfo { node: v.clone() })
.collect()
})
.unwrap_or_default()
}
}
#[derive(Debug, Clone)]
pub struct TypeFieldInfo {
pub node: serde_json::Value,
}
impl TypeFieldInfo {
pub fn field_name(&self) -> Option<&str> {
self.node
.get("field_name")
.and_then(|v| v.as_str())
.or_else(|| self.node.get("name").and_then(|v| v.as_str()))
}
pub fn annotations(&self) -> Vec<String> {
self.node
.get("annotations")
.and_then(|v| v.as_array())
.map(|arr| {
arr.iter()
.filter_map(|v| v.as_str().map(str::to_string))
.collect()
})
.unwrap_or_default()
}
pub fn raw_attributes(&self) -> BTreeMap<String, Vec<String>> {
self.node
.get("raw_attributes")
.and_then(|v| v.as_object())
.map(|obj| {
obj.iter()
.filter_map(|(k, v)| {
let bodies: Vec<String> = v
.as_array()?
.iter()
.filter_map(|x| x.as_str().map(str::to_string))
.collect();
Some((k.clone(), bodies))
})
.collect()
})
.unwrap_or_default()
}
pub fn doccom(&self) -> Option<&str> {
self.node.get("doccom").and_then(|v| v.as_str())
}
}
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
pub struct TypeOverride {
#[serde(default)]
pub macroforge_derives: Vec<String>,
#[serde(default)]
pub annotations: Vec<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub permissions: Option<PermissionsOverride>,
#[serde(default)]
pub events: Vec<EventOverride>,
}
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
pub struct FieldOverride {
#[serde(default)]
pub annotations: Vec<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
pub struct PermissionsOverride {
pub select: String,
pub create: String,
pub update: String,
pub delete: String,
}
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
pub struct EventOverride {
pub name: String,
pub statement: String,
}
#[derive(Debug, Serialize, Deserialize, Default)]
pub struct OutputRulePluginOutput {
#[serde(default)]
pub type_override: TypeOverride,
#[serde(default)]
pub field_overrides: HashMap<String, FieldOverride>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub error: Option<String>,
}
#[macro_export]
macro_rules! define_output_rule_plugin {
(|$ctx:ident : &TypeContext| $body:expr) => {
#[unsafe(no_mangle)]
pub extern "C" fn alloc(size: i32) -> i32 {
let layout = ::std::alloc::Layout::from_size_align(size as usize, 1).unwrap();
unsafe { ::std::alloc::alloc(layout) as i32 }
}
#[unsafe(no_mangle)]
pub extern "C" fn dealloc(ptr: i32, len: i32) {
let layout = ::std::alloc::Layout::from_size_align(len as usize, 1).unwrap();
unsafe { ::std::alloc::dealloc(ptr as *mut u8, layout) }
}
#[unsafe(no_mangle)]
pub extern "C" fn transform_type(ptr: i32, len: i32) -> i64 {
let input_bytes =
unsafe { ::std::slice::from_raw_parts(ptr as *const u8, len as usize) };
let output = match $crate::serde_json::from_slice::<$crate::TypeContext>(input_bytes) {
Ok($ctx) => {
let $ctx = &$ctx;
let result: $crate::OutputRulePluginOutput = (|| $body)();
result
}
Err(e) => $crate::OutputRulePluginOutput {
error: Some(format!("parse error: {}", e)),
..Default::default()
},
};
let bytes = $crate::serde_json::to_vec(&output).unwrap();
let out_ptr = alloc(bytes.len() as i32);
unsafe {
::std::ptr::copy_nonoverlapping(bytes.as_ptr(), out_ptr as *mut u8, bytes.len());
}
((out_ptr as i64) << 32) | (bytes.len() as i64)
}
};
}
pub struct TypeContextBuilder {
variant: BuilderVariant,
pipeline: String,
generator: String,
struct_name: String,
struct_annotations: Vec<String>,
struct_raw_attributes: BTreeMap<String, Vec<serde_json::Value>>,
struct_macroforge_derives: Vec<String>,
struct_rust_derives: Vec<String>,
fields: Vec<serde_json::Value>,
enum_name: String,
enum_annotations: Vec<String>,
enum_raw_attributes: BTreeMap<String, Vec<serde_json::Value>>,
enum_macroforge_derives: Vec<String>,
variants: Vec<serde_json::Value>,
table_name: String,
table_permissions: Option<serde_json::Value>,
table_events: Vec<serde_json::Value>,
table_relation: Option<serde_json::Value>,
}
enum BuilderVariant {
Struct,
Table,
Enum,
}
impl TypeContextBuilder {
pub fn struct_(name: &str) -> Self {
Self::new(BuilderVariant::Struct, name)
}
pub fn table(name: &str) -> Self {
let mut b = Self::new(BuilderVariant::Table, name);
b.table_name = to_snake(name);
b
}
pub fn enum_(name: &str) -> Self {
let mut b = Self::new(BuilderVariant::Enum, name);
b.enum_name = name.to_string();
b
}
fn new(variant: BuilderVariant, name: &str) -> Self {
Self {
variant,
pipeline: "Both".to_string(),
generator: String::new(),
struct_name: name.to_string(),
struct_annotations: Vec::new(),
struct_raw_attributes: BTreeMap::new(),
struct_macroforge_derives: Vec::new(),
struct_rust_derives: Vec::new(),
fields: Vec::new(),
enum_name: String::new(),
enum_annotations: Vec::new(),
enum_raw_attributes: BTreeMap::new(),
enum_macroforge_derives: Vec::new(),
variants: Vec::new(),
table_name: String::new(),
table_permissions: None,
table_events: Vec::new(),
table_relation: None,
}
}
pub fn field(mut self, name: &str, field_type: &str) -> Self {
self.fields.push(serde_json::json!({
"field_name": name,
"field_type": field_type,
"annotations": Vec::<String>::new(),
"validators": Vec::<String>::new(),
"raw_attributes": serde_json::Map::new(),
}));
self
}
pub fn field_with_annotation(mut self, name: &str, field_type: &str, annotation: &str) -> Self {
self.fields.push(serde_json::json!({
"field_name": name,
"field_type": field_type,
"annotations": vec![annotation.to_string()],
"validators": Vec::<String>::new(),
"raw_attributes": serde_json::Map::new(),
}));
self
}
pub fn variant(mut self, name: &str) -> Self {
self.variants.push(serde_json::json!({
"name": name,
"data": serde_json::Value::Null,
"annotations": Vec::<String>::new(),
"raw_attributes": serde_json::Map::new(),
}));
self
}
pub fn with_raw_attr(mut self, name: &str, body: &str) -> Self {
let target = match self.variant {
BuilderVariant::Enum => &mut self.enum_raw_attributes,
_ => &mut self.struct_raw_attributes,
};
target
.entry(name.to_string())
.or_default()
.push(serde_json::Value::String(body.to_string()));
self
}
pub fn with_field_raw_attr(mut self, name: &str, body: &str) -> Self {
let target = match self.variant {
BuilderVariant::Enum => self.variants.last_mut(),
_ => self.fields.last_mut(),
};
if let Some(node) = target
&& let Some(map) = node
.get_mut("raw_attributes")
.and_then(|v| v.as_object_mut())
{
let entry = map
.entry(name.to_string())
.or_insert_with(|| serde_json::Value::Array(Vec::new()));
if let Some(arr) = entry.as_array_mut() {
arr.push(serde_json::Value::String(body.to_string()));
}
}
self
}
pub fn with_macroforge_derives(mut self, derives: &[&str]) -> Self {
let derives: Vec<String> = derives.iter().map(|s| s.to_string()).collect();
match self.variant {
BuilderVariant::Enum => self.enum_macroforge_derives = derives,
_ => self.struct_macroforge_derives = derives,
}
self
}
pub fn table_name_override(mut self, name: &str) -> Self {
self.table_name = name.to_string();
self
}
pub fn with_explicit_permissions(mut self) -> Self {
self.table_permissions = Some(serde_json::json!({
"all_permissions": null,
"select_permissions": "FULL",
"update_permissions": "FULL",
"delete_permissions": "FULL",
"create_permissions": "FULL"
}));
self
}
pub fn with_explicit_events(mut self) -> Self {
self.table_events
.push(serde_json::json!({ "statement": "DEFINE EVENT stub ON TABLE x ..." }));
self
}
pub fn as_relation(mut self) -> Self {
self.table_relation = Some(serde_json::json!({
"edge_name": self.table_name,
"from": Vec::<String>::new(),
"to": Vec::<String>::new(),
"direction": null
}));
self
}
pub fn build(self) -> TypeContext {
let struct_config = serde_json::json!({
"struct_name": self.struct_name,
"fields": self.fields,
"validators": Vec::<String>::new(),
"doccom": serde_json::Value::Null,
"macroforge_derives": self.struct_macroforge_derives,
"annotations": self.struct_annotations,
"pipeline": "Both",
"rust_derives": self.struct_rust_derives,
"raw_attributes": self.struct_raw_attributes,
});
match self.variant {
BuilderVariant::Struct => TypeContext::Struct {
pipeline: self.pipeline,
generator: self.generator,
config: struct_config,
},
BuilderVariant::Table => {
let table_config = serde_json::json!({
"table_name": self.table_name,
"struct_config": struct_config.clone(),
"relation": self.table_relation,
"permissions": self.table_permissions,
"mock_generation_config": serde_json::Value::Null,
"events": self.table_events,
});
TypeContext::Table {
pipeline: self.pipeline,
generator: self.generator,
struct_config,
table_config,
}
}
BuilderVariant::Enum => {
let enum_config = serde_json::json!({
"enum_name": self.enum_name,
"variants": self.variants,
"representation": { "ExternallyTagged": null },
"doccom": serde_json::Value::Null,
"macroforge_derives": self.enum_macroforge_derives,
"annotations": self.enum_annotations,
"pipeline": "Both",
"rust_derives": Vec::<String>::new(),
"raw_attributes": self.enum_raw_attributes,
});
TypeContext::Enum {
pipeline: self.pipeline,
generator: self.generator,
config: enum_config,
}
}
}
}
}
pub fn test_plugin(
plugin_fn: impl Fn(&TypeContext) -> OutputRulePluginOutput,
ctx: TypeContext,
) -> OutputRulePluginOutput {
let json = match &ctx {
TypeContext::Struct {
pipeline,
generator,
config,
} => serde_json::json!({
"kind": "Struct",
"pipeline": pipeline,
"generator": generator,
"config": config,
}),
TypeContext::Table {
pipeline,
generator,
struct_config,
table_config,
} => serde_json::json!({
"kind": "Table",
"pipeline": pipeline,
"generator": generator,
"struct_config": struct_config,
"table_config": table_config,
}),
TypeContext::Enum {
pipeline,
generator,
config,
} => serde_json::json!({
"kind": "Enum",
"pipeline": pipeline,
"generator": generator,
"config": config,
}),
};
let bytes = serde_json::to_vec(&json).expect("Failed to serialize TypeContext test JSON");
let ctx: TypeContext = serde_json::from_slice(&bytes)
.expect("Failed to deserialize TypeContext — roundtrip failed");
let output = plugin_fn(&ctx);
let bytes = serde_json::to_vec(&output).expect("Failed to serialize OutputRulePluginOutput");
let output: OutputRulePluginOutput = serde_json::from_slice(&bytes)
.expect("Failed to deserialize OutputRulePluginOutput — roundtrip failed");
for (field_name, ov) in &output.field_overrides {
assert!(
!ov.annotations.is_empty(),
"field_overrides[\"{}\"].annotations is empty — don't add an override with no annotations",
field_name
);
}
output
}
pub fn print_plugin_output(type_name: &str, output: &OutputRulePluginOutput) {
println!("=== Output for '{}' ===", type_name);
if !output.type_override.macroforge_derives.is_empty() {
println!(
" macroforge_derives: {:?}",
output.type_override.macroforge_derives
);
}
if !output.type_override.annotations.is_empty() {
println!(" annotations: {:?}", output.type_override.annotations);
}
if let Some(ref perms) = output.type_override.permissions {
println!(
" permissions: select={}, create={}, update={}, delete={}",
perms.select, perms.create, perms.update, perms.delete
);
}
for event in &output.type_override.events {
println!(
" event '{}': {}",
event.name,
&event.statement[..event.statement.len().min(80)]
);
}
for (field, ov) in &output.field_overrides {
println!(" field '{}' annotations: {:?}", field, ov.annotations);
}
if let Some(ref err) = output.error {
println!(" ERROR: {}", err);
}
println!();
}
fn to_snake(s: &str) -> String {
let mut result = String::new();
for (i, c) in s.chars().enumerate() {
if c.is_uppercase() {
if i > 0 {
result.push('_');
}
result.push(c.to_ascii_lowercase());
} else {
result.push(c);
}
}
result
}
#[derive(Debug, Deserialize)]
pub struct SyntheticContext {
#[serde(default)]
pub structs: HashMap<String, serde_json::Value>,
#[serde(default)]
pub enums: HashMap<String, serde_json::Value>,
#[serde(default)]
pub tables: HashMap<String, serde_json::Value>,
}
impl SyntheticContext {
pub fn struct_field_type(
&self,
struct_name: &str,
field_name: &str,
) -> Option<serde_json::Value> {
let sc = self.structs.get(struct_name)?;
let fields = sc.get("fields")?.as_array()?;
for f in fields {
if f.get("field_name")?.as_str()? == field_name {
return f.get("field_type").cloned();
}
}
None
}
pub fn table_field_type(
&self,
table_name: &str,
field_name: &str,
) -> Option<serde_json::Value> {
let tc = self.tables.get(table_name)?;
let fields = tc.get("struct_config")?.get("fields")?.as_array()?;
for f in fields {
if f.get("field_name")?.as_str()? == field_name {
return f.get("field_type").cloned();
}
}
None
}
pub fn struct_rust_derives(&self, struct_name: &str) -> Vec<String> {
self.structs
.get(struct_name)
.and_then(|sc| sc.get("rust_derives"))
.and_then(|v| v.as_array())
.map(|arr| {
arr.iter()
.filter_map(|v| v.as_str().map(str::to_string))
.collect()
})
.unwrap_or_default()
}
pub fn struct_annotations(&self, struct_name: &str) -> Vec<String> {
self.structs
.get(struct_name)
.and_then(|sc| sc.get("annotations"))
.and_then(|v| v.as_array())
.map(|arr| {
arr.iter()
.filter_map(|v| v.as_str().map(str::to_string))
.collect()
})
.unwrap_or_default()
}
}
#[derive(Debug, Serialize, Default)]
pub struct SyntheticPluginOutput {
#[serde(default)]
pub new_structs: Vec<serde_json::Value>,
#[serde(default)]
pub new_enums: Vec<serde_json::Value>,
#[serde(default)]
pub new_tables: Vec<serde_json::Value>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub error: Option<String>,
}
pub fn struct_item(name: &str, fields: &[(&str, serde_json::Value)]) -> serde_json::Value {
let field_objs: Vec<serde_json::Value> = fields
.iter()
.map(|(fname, ftype)| {
serde_json::json!({
"field_name": fname,
"field_type": ftype,
"edge_config": serde_json::Value::Null,
"define_config": serde_json::Value::Null,
"format": serde_json::Value::Null,
"validators": [],
"always_regenerate": false,
})
})
.collect();
serde_json::json!({
"struct_name": name,
"fields": field_objs,
"validators": [],
})
}
pub fn enum_item(name: &str, unit_variants: &[&str]) -> serde_json::Value {
let variants: Vec<serde_json::Value> = unit_variants
.iter()
.map(|v| {
serde_json::json!({
"name": v,
"data": serde_json::Value::Null,
"annotations": [],
})
})
.collect();
serde_json::json!({
"enum_name": name,
"variants": variants,
"representation": "ExternallyTagged",
})
}
pub fn table_item(
table_name: &str,
struct_name: &str,
fields: &[(&str, serde_json::Value)],
) -> serde_json::Value {
serde_json::json!({
"table_name": table_name,
"struct_config": struct_item(struct_name, fields),
"relation": serde_json::Value::Null,
"permissions": serde_json::Value::Null,
"mock_generation_config": serde_json::Value::Null,
})
}
pub fn string_type() -> serde_json::Value {
serde_json::json!("String")
}
pub fn bool_type() -> serde_json::Value {
serde_json::json!("Bool")
}
pub fn i64_type() -> serde_json::Value {
serde_json::json!("I64")
}
pub fn f64_type() -> serde_json::Value {
serde_json::json!("F64")
}
pub fn option_of(inner: serde_json::Value) -> serde_json::Value {
serde_json::json!({ "Option": inner })
}
pub fn vec_of(inner: serde_json::Value) -> serde_json::Value {
serde_json::json!({ "Vec": inner })
}
#[macro_export]
macro_rules! define_synthetic_item_plugin {
(|$ctx:ident : &SyntheticContext| $body:expr) => {
#[unsafe(no_mangle)]
pub extern "C" fn alloc(size: i32) -> i32 {
let layout = ::std::alloc::Layout::from_size_align(size as usize, 1).unwrap();
unsafe { ::std::alloc::alloc(layout) as i32 }
}
#[unsafe(no_mangle)]
pub extern "C" fn dealloc(ptr: i32, len: i32) {
let layout = ::std::alloc::Layout::from_size_align(len as usize, 1).unwrap();
unsafe { ::std::alloc::dealloc(ptr as *mut u8, layout) }
}
#[unsafe(no_mangle)]
pub extern "C" fn generate_items(ptr: i32, len: i32) -> i64 {
let input_bytes =
unsafe { ::std::slice::from_raw_parts(ptr as *const u8, len as usize) };
let output =
match $crate::serde_json::from_slice::<$crate::SyntheticContext>(input_bytes) {
Ok($ctx) => {
let $ctx = &$ctx;
let result: $crate::SyntheticPluginOutput = (|| $body)();
result
}
Err(e) => $crate::SyntheticPluginOutput {
error: Some(format!("parse error: {}", e)),
..Default::default()
},
};
let bytes = $crate::serde_json::to_vec(&output).unwrap();
let out_ptr = alloc(bytes.len() as i32);
unsafe {
::std::ptr::copy_nonoverlapping(bytes.as_ptr(), out_ptr as *mut u8, bytes.len());
}
((out_ptr as i64) << 32) | (bytes.len() as i64)
}
};
}