1
0

Merge branch 'dev'

This commit is contained in:
Kozlov Maxim 2023-10-25 11:09:07 +06:00
commit 28951823a8
7 changed files with 265 additions and 44 deletions

View File

@ -47,8 +47,8 @@ unsafe extern "system" fn done<T: AddInWrapper>(this: &mut This<0, T>) {
component.addin.done()
}
impl<T: AddInWrapper> InitDoneBaseVTable<T> {
pub fn new() -> Self {
impl<T: AddInWrapper> Default for InitDoneBaseVTable<T> {
fn default() -> Self {
Self {
dtor: 0,
#[cfg(target_family = "unix")]

View File

@ -1,7 +1,7 @@
use std::{
ffi::c_long,
ptr::{self},
slice::from_raw_parts,
slice::from_raw_parts_mut,
};
use crate::interface::AddInWrapper;
@ -56,14 +56,14 @@ pub struct LanguageExtenderBaseVTable<T: AddInWrapper> {
call_as_proc: unsafe extern "system" fn(
&mut This<1, T>,
c_long,
*const TVariant,
*mut TVariant,
c_long,
) -> bool,
call_as_func: unsafe extern "system" fn(
&mut This<1, T>,
c_long,
&mut TVariant,
*const TVariant,
*mut TVariant,
c_long,
) -> bool,
}
@ -79,7 +79,7 @@ unsafe extern "system" fn register_extension_as<T: AddInWrapper>(
let extension_name = component.addin.register_extension_as();
let Some(ptr) = allocator.alloc_str(extension_name.len()) else {
let Ok(ptr) = allocator.alloc_str(extension_name.len()) else {
return false;
};
ptr::copy_nonoverlapping(
@ -123,7 +123,7 @@ unsafe extern "system" fn get_prop_name<T: AddInWrapper>(
let Some(prop_name) = component.addin.get_prop_name(num as usize, alias as usize) else {
return ptr::null();
};
let Some(ptr) = allocator.alloc_str(prop_name.len()) else {
let Ok(ptr) = allocator.alloc_str(prop_name.len()) else {
return ptr::null();
};
ptr::copy_nonoverlapping(prop_name.as_ptr(), ptr.as_ptr(), prop_name.len());
@ -207,7 +207,7 @@ unsafe extern "system" fn get_method_name<T: AddInWrapper>(
let Some(method_name) = component.addin.get_method_name(num as usize, alias as usize) else {
return ptr::null();
};
let Some(ptr) = allocator.alloc_str(method_name.len()) else {
let Ok(ptr) = allocator.alloc_str(method_name.len()) else {
return ptr::null();
};
@ -264,53 +264,116 @@ unsafe extern "system" fn has_ret_val<T: AddInWrapper>(
unsafe extern "system" fn call_as_proc<T: AddInWrapper>(
this: &mut This<1, T>,
method_num: c_long,
params: *const TVariant,
params: *mut TVariant,
size_array: c_long,
) -> bool {
let component = this.get_component();
let param_values = from_raw_parts(params, size_array as usize)
let Some(mem_mngr) = component.memory else { return false; };
let parameters_raw = from_raw_parts_mut(params, size_array as usize);
let mut parameters_values = parameters_raw
.iter()
.map(ParamValue::from)
.collect::<Vec<ParamValue>>();
let parameters_values_buf = parameters_values.clone();
component
let call_result = component
.addin
.call_as_proc(method_num as usize, param_values.as_slice())
.call_as_proc(method_num as usize, &mut parameters_values);
if !call_result {
return false;
}
if parameters_values.len() != parameters_values_buf.len() {
return false;
}
for i in 0..parameters_values.len() {
let raw_param = &mut parameters_raw[i];
if parameters_values_buf[i] == parameters_values[i] {
continue;
}
match &parameters_values[i] {
ParamValue::Str(v) => {
let Ok(_) = raw_param.update_to_str(mem_mngr, v) else { return false; };
}
ParamValue::Blob(v) => {
let Ok(_) = raw_param.update_to_blob(mem_mngr, v) else { return false; };
}
ParamValue::Bool(v) => raw_param.update_to_bool(*v),
ParamValue::I32(v) => raw_param.update_to_i32(*v),
ParamValue::F64(v) => raw_param.update_to_f64(*v),
ParamValue::Date(v) => raw_param.update_to_date(*v),
ParamValue::Empty => {}
}
}
true
}
unsafe extern "system" fn call_as_func<T: AddInWrapper>(
this: &mut This<1, T>,
method_num: c_long,
ret_value: &mut TVariant,
params: *const TVariant,
params: *mut TVariant,
size_array: c_long,
) -> bool {
let component = this.get_component();
let Some(mem) = component.memory else {
return false;
};
let Some(mem_mngr) = component.memory else { return false; };
let mut result = true;
let return_value = ReturnValue {
mem,
mem: mem_mngr,
variant: ret_value,
result: &mut result,
};
let param_values = from_raw_parts(params, size_array as usize)
let parameters_raw = from_raw_parts_mut(params, size_array as usize);
let mut parameters_values = parameters_raw
.iter()
.map(ParamValue::from)
.collect::<Vec<ParamValue>>();
let parameters_values_buf = parameters_values.clone();
component.addin.call_as_func(
let call_result = component.addin.call_as_func(
method_num as usize,
param_values.as_slice(),
&mut parameters_values,
return_value,
) && result
);
if !call_result {
return false;
}
if !result {
return false;
}
if parameters_values.len() != parameters_values_buf.len() {
return false;
}
for i in 0..parameters_values.len() {
let raw_param = &mut parameters_raw[i];
if parameters_values_buf[i] == parameters_values[i] {
continue;
}
match &parameters_values[i] {
ParamValue::Str(v) => {
let Ok(_) = raw_param.update_to_str(mem_mngr, v) else { return false; };
}
ParamValue::Blob(v) => {
let Ok(_) = raw_param.update_to_blob(mem_mngr, v) else { return false; };
}
ParamValue::Bool(v) => raw_param.update_to_bool(*v),
ParamValue::I32(v) => raw_param.update_to_i32(*v),
ParamValue::F64(v) => raw_param.update_to_f64(*v),
ParamValue::Date(v) => raw_param.update_to_date(*v),
ParamValue::Empty => {}
}
}
true
}
impl<T: AddInWrapper> LanguageExtenderBaseVTable<T> {
pub fn new() -> Self {
impl<T: AddInWrapper> Default for LanguageExtenderBaseVTable<T> {
fn default() -> Self {
Self {
dtor: 0,
#[cfg(target_family = "unix")]

View File

@ -25,20 +25,28 @@ pub struct MemoryManager {
vptr: &'static MemoryManagerVTable,
}
pub struct AllocationError;
impl MemoryManager {
/// Safe wrapper around `alloc_memory` method of the MemoryManager object
/// to allocate memory for byte array
/// # Arguments
/// * `size` - size of the memory block to allocate
/// # Returns
/// `Option<NonNull<u8>>` - pointer to the allocated memory block
pub fn alloc_blob(&self, size: usize) -> Option<NonNull<u8>> {
/// `Result<NonNull<u8>, AllocationError>` - pointer to the allocated memory block
pub fn alloc_blob(
&self,
size: usize,
) -> Result<NonNull<u8>, AllocationError> {
let mut ptr = ptr::null_mut::<c_void>();
unsafe {
if (self.vptr.alloc_memory)(self, &mut ptr, size as c_ulong) {
NonNull::new(ptr as *mut u8)
if (self.vptr.alloc_memory)(self, &mut ptr, size as c_ulong * 2) {
match NonNull::new(ptr as *mut u8) {
Some(ptr) => Ok(ptr),
None => Err(AllocationError),
}
} else {
None
Err(AllocationError)
}
}
}
@ -48,15 +56,27 @@ impl MemoryManager {
/// # Arguments
/// * `size` - size of the memory block to allocate
/// # Returns
/// `Option<NonNull<u16>>` - pointer to the allocated memory block
pub fn alloc_str(&self, size: usize) -> Option<NonNull<u16>> {
/// `Result<NonNull<u16>, AllocationError>` - pointer to the allocated memory block
pub fn alloc_str(
&self,
size: usize,
) -> Result<NonNull<u16>, AllocationError> {
let mut ptr = ptr::null_mut::<c_void>();
unsafe {
if (self.vptr.alloc_memory)(self, &mut ptr, size as c_ulong * 2) {
NonNull::new(ptr as *mut u16)
match NonNull::new(ptr as *mut u16) {
Some(ptr) => Ok(ptr),
None => Err(AllocationError),
}
} else {
None
Err(AllocationError)
}
}
}
pub fn free_memory(&self, ptr: &mut *mut c_void) {
unsafe {
(self.vptr.free_memory)(self, ptr);
}
}
}

View File

@ -110,8 +110,8 @@ pub unsafe fn create_component<T: AddInWrapper>(
component: *mut *mut c_void,
addin: T,
) -> c_long {
let vptr1 = Box::new(InitDoneBaseVTable::new());
let vptr2 = Box::new(LanguageExtenderBaseVTable::new());
let vptr1 = Box::<InitDoneBaseVTable<T>>::default();
let vptr2 = Box::<LanguageExtenderBaseVTable<T>>::default();
let vptr3 = Box::new(LocaleBaseVTable {
dtor: 0,
#[cfg(target_family = "unix")]

View File

@ -1,7 +1,11 @@
use chrono::{Datelike, Offset, Timelike};
use std::{ffi::c_int, ptr, slice::from_raw_parts};
use std::{
ffi::{c_int, c_void},
ptr,
slice::{from_raw_parts, from_raw_parts_mut},
};
use super::memory_manager::MemoryManager;
use super::memory_manager::{AllocationError, MemoryManager};
/// Type representing 1C date and time values
/// # Fields
@ -121,6 +125,38 @@ impl From<Tm> for chrono::DateTime<chrono::FixedOffset> {
}
}
#[cfg(target_family = "unix")]
impl PartialEq for Tm {
fn eq(&self, other: &Self) -> bool {
self.sec == other.sec
&& self.min == other.min
&& self.hour == other.hour
&& self.mday == other.mday
&& self.mon == other.mon
&& self.year == other.year
&& self.wday == other.wday
&& self.yday == other.yday
&& self.isdst == other.isdst
&& self.gmtoff == other.gmtoff
&& self.zone == other.zone
}
}
#[cfg(target_family = "windows")]
impl PartialEq for Tm {
fn eq(&self, other: &Self) -> bool {
self.sec == other.sec
&& self.min == other.min
&& self.hour == other.hour
&& self.mday == other.mday
&& self.mon == other.mon
&& self.year == other.year
&& self.wday == other.wday
&& self.yday == other.yday
&& self.isdst == other.isdst
}
}
/// Type representing 1C variant values
/// # Fields
/// `mem` - pointer to the MemoryManager object
@ -165,7 +201,7 @@ impl<'a> ReturnValue<'a> {
/// Sets the value of the ReturnValue object to UTF-16 `&[u16]`
pub fn set_str(self, val: &[u16]) {
let Some(ptr) = self.mem.alloc_str(val.len()) else {
let Ok(ptr) = self.mem.alloc_str(val.len()) else {
*self.result = false;
return;
};
@ -181,7 +217,7 @@ impl<'a> ReturnValue<'a> {
/// Sets the value of the ReturnValue object to blob `&[u8]`
pub fn set_blob(self, val: &[u8]) {
let Some(ptr) = self.mem.alloc_blob(val.len()) else {
let Ok(ptr) = self.mem.alloc_blob(val.len()) else {
*self.result = false;
return;
};
@ -197,6 +233,7 @@ impl<'a> ReturnValue<'a> {
}
/// Represents 1C variant values for parameters
#[derive(Clone)]
pub enum ParamValue {
/// Empty value
Empty,
@ -214,6 +251,21 @@ pub enum ParamValue {
Blob(Vec<u8>),
}
impl<'a> PartialEq for ParamValue {
fn eq(&self, other: &Self) -> bool {
match (self, other) {
(Self::Empty, Self::Empty) => true,
(Self::Bool(a), Self::Bool(b)) => a == b,
(Self::I32(a), Self::I32(b)) => a == b,
(Self::F64(a), Self::F64(b)) => a == b,
(Self::Date(a), Self::Date(b)) => a == b,
(Self::Str(a), Self::Str(b)) => a == b,
(Self::Blob(a), Self::Blob(b)) => a == b,
_ => false,
}
}
}
impl<'a> From<&'a TVariant> for ParamValue {
fn from(param: &'a TVariant) -> ParamValue {
unsafe {
@ -245,7 +297,7 @@ impl<'a> From<&'a TVariant> for ParamValue {
#[repr(u16)]
#[allow(dead_code)]
enum VariantType {
pub enum VariantType {
Empty = 0,
Null,
Int16, //int16_t
@ -281,7 +333,7 @@ enum VariantType {
/// * `len` - length of the data
#[repr(C)]
#[derive(Clone, Copy)]
struct DataStr {
pub struct DataStr {
pub ptr: *mut u16,
pub len: u32,
}
@ -292,7 +344,7 @@ struct DataStr {
/// * `len` - length of the data
#[repr(C)]
#[derive(Clone, Copy)]
struct DataBlob {
pub struct DataBlob {
pub ptr: *mut u8,
pub len: u32,
}
@ -306,7 +358,7 @@ struct DataBlob {
/// * `data_str` - UTF-16 string value
/// * `data_blob` - blob value
#[repr(C)]
union VariantValue {
pub union VariantValue {
pub bool: bool,
pub i32: i32,
pub f64: f64,
@ -322,3 +374,68 @@ pub struct TVariant {
elements: u32, //Dimension for an one-dimensional array in pvarVal
vt: VariantType,
}
impl TVariant {
/// # Safety
/// This function is unsafe because it manipulates pointers, provided by the 1C platform.
/// Function is safe as long as 1C platform provides valid pointers.
pub unsafe fn update_to_str(
&mut self,
mem_mngr: &MemoryManager,
v: &[u16],
) -> Result<u32, AllocationError> {
let mut old_pointer = self.value.data_str.ptr;
let ptr = mem_mngr.alloc_str(v.len())?;
ptr::copy_nonoverlapping(v.as_ptr(), ptr.as_ptr(), v.len());
self.value.data_str.ptr = ptr.as_ptr();
self.value.data_str.len = v.len() as u32;
mem_mngr.free_memory(&mut old_pointer.cast::<c_void>());
self.vt = VariantType::WStr;
Ok(self.value.data_str.len)
}
pub unsafe fn update_to_blob(
&mut self,
mem_mngr: &MemoryManager,
v: &[u8],
) -> Result<u32, AllocationError> {
let mut old_pointer = self.value.data_blob.ptr;
let ptr = mem_mngr.alloc_blob(v.len())?;
ptr::copy_nonoverlapping(v.as_ptr(), ptr.as_ptr(), v.len());
self.value.data_blob.ptr = ptr.as_ptr();
self.value.data_blob.len = v.len() as u32;
mem_mngr.free_memory(&mut old_pointer.cast::<c_void>());
self.vt = VariantType::Blob;
Ok(self.value.data_blob.len)
}
pub fn update_to_bool(&mut self, v: bool) {
self.value.bool = v;
self.vt = VariantType::Bool;
}
pub fn update_to_i32(&mut self, v: i32) {
self.value.i32 = v;
self.vt = VariantType::Int32;
}
pub fn update_to_f64(&mut self, v: f64) {
self.value.f64 = v;
self.vt = VariantType::Double;
}
pub fn update_to_date(&mut self, v: Tm) {
self.value.tm = v;
self.vt = VariantType::Time;
}
}

View File

@ -43,6 +43,27 @@ pub fn os_string_nil(s: &str) -> Vec<u16> {
.collect()
}
/// Helper function to convert Rust string to UTF-16 string
/// # Arguments
/// * `s` - Rust string
/// # Returns
/// `Vec<u16>` - UTF-16 string without null terminator
#[cfg(target_family = "unix")]
pub fn os_string(s: &str) -> Vec<u16> {
s.encode_utf16().collect()
}
/// Helper function to convert Rust string to UTF-16 string
/// # Arguments
/// * `s` - Rust string
/// # Returns
/// `Vec<u16>` - UTF-16 string with null terminator
#[cfg(target_family = "windows")]
pub fn os_string(s: &str) -> Vec<u16> {
let os_str = std::ffi::OsStr::new(s);
std::os::windows::prelude::OsStrExt::encode_wide(os_str).collect()
}
/// Helper function to convert UTF-16 string to Rust string
/// # Arguments
/// * `s` - UTF-16 string

View File

@ -160,7 +160,7 @@ pub trait AddInWrapper {
fn call_as_proc(
&mut self,
method_num: usize,
params: &[ParamValue],
params: &mut [ParamValue],
) -> bool;
/// Equivalent to `CallAsFunc` from Native API interface and is used to call method
@ -174,7 +174,7 @@ pub trait AddInWrapper {
fn call_as_func(
&mut self,
method_num: usize,
params: &[ParamValue],
params: &mut [ParamValue],
val: ReturnValue,
) -> bool;