use std::ffi::CString;
use std::os::raw::c_char;
use std::ptr;
use super::conversions::{c_str_to_rust, cast_report};
use super::errors::CErrorCode;
use super::types::{CFieldSelector, CReport};
use crate::utils::json_optimizer::{FieldSelector, OptimizedSerializer, SerializationOptions};
pub(crate) struct FieldSelectorInternal {
pub inc_fields: Vec<String>,
pub exc_fields: Vec<String>,
pub inc_sections: Vec<String>,
pub exc_sections: Vec<String>,
}
impl FieldSelectorInternal {
fn new() -> Self {
Self {
inc_fields: Vec::new(),
exc_fields: Vec::new(),
inc_sections: Vec::new(),
exc_sections: Vec::new(),
}
}
fn to_selector(&self) -> FieldSelector {
let mut builder = FieldSelector::builder();
for f in &self.inc_fields {
builder = builder.include_field(f.clone());
}
for f in &self.exc_fields {
builder = builder.exclude_field(f.clone());
}
for s in &self.inc_sections {
builder = builder.include_section(s.clone());
}
for s in &self.exc_sections {
builder = builder.exclude_section(s.clone());
}
builder.build()
}
}
#[no_mangle]
pub extern "C" fn wqa_field_selector_new() -> *mut CFieldSelector {
Box::into_raw(Box::new(FieldSelectorInternal::new())) as *mut CFieldSelector
}
#[no_mangle]
pub extern "C" fn wqa_field_selector_free(selector: *mut CFieldSelector) {
if !selector.is_null() {
unsafe {
let _ = Box::from_raw(selector as *mut FieldSelectorInternal);
}
}
}
#[no_mangle]
pub extern "C" fn wqa_field_selector_include_field(
sel: *mut CFieldSelector,
field: *const c_char,
) -> CErrorCode {
if sel.is_null() || field.is_null() {
return CErrorCode::InvalidPointer;
}
let s = match unsafe { c_str_to_rust(field) } {
Some(s) => s.to_string(),
None => return CErrorCode::Utf8Error,
};
unsafe {
(&mut *(sel as *mut FieldSelectorInternal))
.inc_fields
.push(s);
}
CErrorCode::Success
}
#[no_mangle]
pub extern "C" fn wqa_field_selector_exclude_field(
sel: *mut CFieldSelector,
field: *const c_char,
) -> CErrorCode {
if sel.is_null() || field.is_null() {
return CErrorCode::InvalidPointer;
}
let s = match unsafe { c_str_to_rust(field) } {
Some(s) => s.to_string(),
None => return CErrorCode::Utf8Error,
};
unsafe {
(&mut *(sel as *mut FieldSelectorInternal))
.exc_fields
.push(s);
}
CErrorCode::Success
}
#[no_mangle]
pub extern "C" fn wqa_field_selector_include_section(
sel: *mut CFieldSelector,
sec: *const c_char,
) -> CErrorCode {
if sel.is_null() || sec.is_null() {
return CErrorCode::InvalidPointer;
}
let s = match unsafe { c_str_to_rust(sec) } {
Some(s) => s.to_string(),
None => return CErrorCode::Utf8Error,
};
unsafe {
(&mut *(sel as *mut FieldSelectorInternal))
.inc_sections
.push(s);
}
CErrorCode::Success
}
#[no_mangle]
pub extern "C" fn wqa_field_selector_exclude_section(
sel: *mut CFieldSelector,
sec: *const c_char,
) -> CErrorCode {
if sel.is_null() || sec.is_null() {
return CErrorCode::InvalidPointer;
}
let s = match unsafe { c_str_to_rust(sec) } {
Some(s) => s.to_string(),
None => return CErrorCode::Utf8Error,
};
unsafe {
(&mut *(sel as *mut FieldSelectorInternal))
.exc_sections
.push(s);
}
CErrorCode::Success
}
#[no_mangle]
pub extern "C" fn wqa_report_to_json_with_selector(
report: *const CReport,
selector: *const CFieldSelector,
compact: bool,
) -> *mut c_char {
if report.is_null() {
return ptr::null_mut();
}
let r = match unsafe { cast_report(report) } {
Some(r) => r,
None => return ptr::null_mut(),
};
let json = if selector.is_null() {
if compact {
serde_json::to_string(&r.report)
} else {
serde_json::to_string_pretty(&r.report)
}
} else {
let si = unsafe { &*(selector as *const FieldSelectorInternal) };
let fs = si.to_selector();
let opts = SerializationOptions {
compact,
skip_empty_fields: true,
minimal_output: false,
streaming: false,
buffer_size: 8192,
};
OptimizedSerializer::serialize_with_selector(&r.report, &fs, Some(&opts))
};
match json {
Ok(j) => match CString::new(j) {
Ok(cs) => cs.into_raw(),
Err(_) => ptr::null_mut(),
},
Err(_) => ptr::null_mut(),
}
}
#[no_mangle]
pub extern "C" fn wqa_report_to_ultra_compact_json(report: *const CReport) -> *mut c_char {
if report.is_null() {
return ptr::null_mut();
}
let r = match unsafe { cast_report(report) } {
Some(r) => r,
None => return ptr::null_mut(),
};
let sel = FieldSelector::builder()
.include_fields(["url", "score", "verdict", "version"])
.include_field("metrics.html_analysis.content.word_count")
.build();
let opts = SerializationOptions {
compact: true,
skip_empty_fields: true,
minimal_output: true,
streaming: false,
buffer_size: 4096,
};
match OptimizedSerializer::serialize_with_selector(&r.report, &sel, Some(&opts)) {
Ok(j) => match CString::new(j) {
Ok(cs) => cs.into_raw(),
Err(_) => ptr::null_mut(),
},
Err(_) => ptr::null_mut(),
}
}