use std::ffi::c_void;
pub const HARN_NATIVE_LINT_ABI_VERSION: u32 = 1;
pub const HARN_NATIVE_LINT_REGISTER_SYMBOL: &[u8] = b"harn_native_lint_register_v1\0";
pub type HarnNativeLintRegisterFn = unsafe extern "C" fn(*mut HarnNativeRuleRegistry);
#[repr(C)]
#[derive(Clone, Copy, Debug)]
pub struct HarnNativeStr {
pub ptr: *const u8,
pub len: usize,
}
impl HarnNativeStr {
pub const fn empty() -> Self {
Self {
ptr: std::ptr::null(),
len: 0,
}
}
pub fn borrowed(value: &str) -> Self {
Self {
ptr: value.as_ptr(),
len: value.len(),
}
}
pub unsafe fn as_str(&self) -> Option<&str> {
if self.len == 0 {
return Some("");
}
if self.ptr.is_null() {
return None;
}
let bytes = unsafe { std::slice::from_raw_parts(self.ptr, self.len) };
std::str::from_utf8(bytes).ok()
}
}
impl Default for HarnNativeStr {
fn default() -> Self {
Self::empty()
}
}
#[repr(C)]
#[derive(Clone, Copy, Debug, Default)]
pub struct HarnNativeSpan {
pub start: usize,
pub end: usize,
pub line: usize,
pub column: usize,
pub end_line: usize,
}
impl HarnNativeSpan {
pub const fn new(start: usize, end: usize, line: usize, column: usize) -> Self {
Self {
start,
end,
line,
column,
end_line: line,
}
}
}
pub const HARN_NATIVE_SEVERITY_INFO: u32 = 0;
pub const HARN_NATIVE_SEVERITY_WARNING: u32 = 1;
pub const HARN_NATIVE_SEVERITY_ERROR: u32 = 2;
#[repr(C)]
#[derive(Clone, Copy, Debug)]
pub struct HarnNativeFixEdit {
pub span: HarnNativeSpan,
pub replacement: HarnNativeStr,
}
impl HarnNativeFixEdit {
pub fn replace(span: HarnNativeSpan, replacement: &str) -> Self {
Self {
span,
replacement: HarnNativeStr::borrowed(replacement),
}
}
}
#[repr(C)]
#[derive(Clone, Copy, Debug)]
pub struct HarnNativeDiagnostic {
pub message: HarnNativeStr,
pub severity: u32,
pub span: HarnNativeSpan,
pub suggestion: HarnNativeStr,
pub fixes: *const HarnNativeFixEdit,
pub fix_count: usize,
}
impl HarnNativeDiagnostic {
pub fn warning(message: &str, span: HarnNativeSpan) -> Self {
Self {
message: HarnNativeStr::borrowed(message),
severity: HARN_NATIVE_SEVERITY_WARNING,
span,
suggestion: HarnNativeStr::empty(),
fixes: std::ptr::null(),
fix_count: 0,
}
}
pub fn with_suggestion(mut self, suggestion: &str) -> Self {
self.suggestion = HarnNativeStr::borrowed(suggestion);
self
}
pub fn with_fixes(mut self, fixes: &[HarnNativeFixEdit]) -> Self {
self.fixes = fixes.as_ptr();
self.fix_count = fixes.len();
self
}
}
#[repr(C)]
#[derive(Clone, Copy, Debug)]
pub struct HarnNativeRuleInput {
pub source: HarnNativeStr,
pub file_path: HarnNativeStr,
}
#[repr(C)]
#[derive(Clone, Copy, Debug)]
pub struct HarnNativeNode {
pub span: HarnNativeSpan,
pub text: HarnNativeStr,
}
#[repr(C)]
#[derive(Clone, Copy)]
pub struct HarnNativeDiagnosticSink {
pub data: *mut c_void,
pub push: Option<unsafe extern "C" fn(*mut c_void, HarnNativeDiagnostic)>,
}
impl HarnNativeDiagnosticSink {
pub unsafe fn push(&self, diagnostic: HarnNativeDiagnostic) {
if let Some(push) = self.push {
unsafe { push(self.data, diagnostic) };
}
}
}
pub type HarnNativeCheckProgramFn = unsafe extern "C" fn(
user_data: *mut c_void,
input: HarnNativeRuleInput,
sink: HarnNativeDiagnosticSink,
);
pub type HarnNativeCheckNodeFn = unsafe extern "C" fn(
user_data: *mut c_void,
input: HarnNativeRuleInput,
node: HarnNativeNode,
sink: HarnNativeDiagnosticSink,
);
pub type HarnNativeDropUserDataFn = unsafe extern "C" fn(user_data: *mut c_void);
#[repr(C)]
#[derive(Clone, Copy)]
pub struct HarnNativeRuleDescriptor {
pub abi_version: u32,
pub id: HarnNativeStr,
pub user_data: *mut c_void,
pub check_program: Option<HarnNativeCheckProgramFn>,
pub check_node: Option<HarnNativeCheckNodeFn>,
pub finalize: Option<HarnNativeCheckProgramFn>,
pub drop_user_data: Option<HarnNativeDropUserDataFn>,
}
impl HarnNativeRuleDescriptor {
pub fn stateless(id: &str, check_program: HarnNativeCheckProgramFn) -> Self {
Self {
abi_version: HARN_NATIVE_LINT_ABI_VERSION,
id: HarnNativeStr::borrowed(id),
user_data: std::ptr::null_mut(),
check_program: Some(check_program),
check_node: None,
finalize: None,
drop_user_data: None,
}
}
}
#[repr(C)]
pub struct HarnNativeRuleRegistry {
pub data: *mut c_void,
pub add_rule: Option<unsafe extern "C" fn(*mut c_void, HarnNativeRuleDescriptor)>,
}
impl HarnNativeRuleRegistry {
pub unsafe fn add(&mut self, descriptor: HarnNativeRuleDescriptor) {
if let Some(add_rule) = self.add_rule {
unsafe { add_rule(self.data, descriptor) };
}
}
}