mirror of git://git.psyc.eu/libpsyc
125 lines
4.5 KiB
Rust
125 lines
4.5 KiB
Rust
use text_types::*;
|
|
use types::PsycString;
|
|
use method_types::PsycMethod;
|
|
use util;
|
|
use std::os::raw::c_char;
|
|
use std::os::raw::c_void;
|
|
use std::ptr;
|
|
use std::mem;
|
|
use std::marker::PhantomData;
|
|
|
|
extern "C" {
|
|
fn psyc_text_state_init(state: *mut PsycTextState,
|
|
tmpl: *const c_char,
|
|
tmplen: usize,
|
|
buffer: *mut c_char,
|
|
buflen: usize);
|
|
|
|
fn psyc_text_state_init_custom(state: *mut PsycTextState,
|
|
tmpl_: *const c_char,
|
|
tmplen: usize,
|
|
buffer: *mut c_char,
|
|
buflen: usize,
|
|
ope: *const c_char,
|
|
opelen: usize,
|
|
clo: *const c_char,
|
|
clolen: usize);
|
|
|
|
fn psyc_text_buffer_set(state: *mut PsycTextState,
|
|
buffer: *mut c_char,
|
|
length: usize);
|
|
|
|
fn psyc_text_bytes_written(state: *const PsycTextState) -> usize;
|
|
|
|
fn psyc_text(state: *mut PsycTextState,
|
|
get_value: extern fn(*const c_void,
|
|
*const c_char,
|
|
usize,
|
|
*mut PsycString)
|
|
-> PsycTextValueRC,
|
|
get_value_cls: *const c_void)
|
|
-> PsycTextRC;
|
|
|
|
fn psyc_template(mc: PsycMethod, len: *mut usize) -> *const c_char;
|
|
}
|
|
|
|
extern "C" fn callback(cls: *const c_void,
|
|
name: *const c_char,
|
|
namelen: usize,
|
|
value: *mut PsycString)
|
|
-> PsycTextValueRC {
|
|
let get_value: &&for<'a> Fn(&'a [u8]) -> Option<&[u8]> = unsafe {
|
|
mem::transmute(cls)
|
|
};
|
|
let name_slice = unsafe {
|
|
util::cstring_to_slice(name, namelen)
|
|
};
|
|
match get_value(name_slice) {
|
|
None => PsycTextValueRC::PSYC_TEXT_VALUE_NOT_FOUND,
|
|
Some(val) => {
|
|
let mut v: &mut PsycString = unsafe {&mut *value};
|
|
v.data = val.as_ptr() as *const c_char;
|
|
v.length = val.len();
|
|
PsycTextValueRC::PSYC_TEXT_VALUE_FOUND
|
|
}
|
|
}
|
|
}
|
|
|
|
pub struct Text<'a> {
|
|
state: PsycTextState,
|
|
phantom_template: PhantomData<&'a Vec<u8>>,
|
|
}
|
|
|
|
impl<'a> Text<'a> {
|
|
pub fn new(template: &'a [u8]) -> Self {
|
|
let mut state: PsycTextState;
|
|
let template_ptr = template.as_ptr() as *const c_char;
|
|
unsafe {
|
|
state = mem::uninitialized();
|
|
let state_ptr = &mut state as *mut PsycTextState;
|
|
psyc_text_state_init(state_ptr,
|
|
template_ptr,
|
|
template.len(),
|
|
ptr::null_mut(),
|
|
0);
|
|
}
|
|
Text {
|
|
state: state,
|
|
phantom_template: PhantomData,
|
|
}
|
|
}
|
|
|
|
pub fn substitute_variables<'b, F>(&mut self,
|
|
get_value: F,
|
|
buffer: &'b mut [u8])
|
|
-> SubstitutionResult
|
|
where F: Fn(&'a [u8]) -> Option<&[u8]> {
|
|
let state_ptr = &mut self.state as *mut PsycTextState;
|
|
let buffer_ptr = buffer.as_mut_ptr() as *mut c_char;
|
|
let trait_obj: &Fn(&'a [u8]) -> Option<&[u8]> = &get_value;
|
|
let trait_obj_ptr: *const c_void = unsafe {mem::transmute(&trait_obj)};
|
|
unsafe {
|
|
psyc_text_buffer_set(state_ptr, buffer_ptr, buffer.len());
|
|
let result = psyc_text(state_ptr, callback, trait_obj_ptr);
|
|
match result {
|
|
PsycTextRC::PSYC_TEXT_NO_SUBST => SubstitutionResult::NoSubstitution,
|
|
PsycTextRC::PSYC_TEXT_COMPLETE => SubstitutionResult::Complete {
|
|
bytes_written: psyc_text_bytes_written(state_ptr)
|
|
},
|
|
PsycTextRC::PSYC_TEXT_INCOMPLETE => SubstitutionResult::Incomplete {
|
|
bytes_written: psyc_text_bytes_written(state_ptr)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
pub fn template(method: PsycMethod) -> &'static [u8] {
|
|
let mut result: PsycString;
|
|
unsafe {
|
|
result = mem::uninitialized();
|
|
result.data = psyc_template(method, &mut result.length as *mut usize);
|
|
util::cstring_to_slice(result.data, result.length)
|
|
}
|
|
}
|
|
}
|