You've already forked OpenIntegrations
mirror of
https://github.com/Bayselonarrend/OpenIntegrations.git
synced 2025-08-10 22:41:43 +02:00
Начало PG
This commit is contained in:
1273
src/addins/postgre/Cargo.lock
generated
Normal file
1273
src/addins/postgre/Cargo.lock
generated
Normal file
File diff suppressed because it is too large
Load Diff
21
src/addins/postgre/Cargo.toml
Normal file
21
src/addins/postgre/Cargo.toml
Normal file
@@ -0,0 +1,21 @@
|
||||
[package]
|
||||
name = "opi_postgres"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[lib]
|
||||
crate-type = ["cdylib"]
|
||||
|
||||
[profile.release]
|
||||
lto = "fat" # Enable Link Time Optimization
|
||||
codegen-units = 1 # Reduce number of codegen units to increase optimizations.
|
||||
panic = "abort" # Abort on panic
|
||||
strip = true # Automatically strip symbols from the binary.
|
||||
opt-level = "z"
|
||||
|
||||
[dependencies]
|
||||
addin1c = "0.5.0"
|
||||
postgres = { version = "0.19.9"}
|
||||
serde_json = "1.0"
|
||||
base64 = "0.22.1"
|
||||
serde_postgres = { version = "0.2.0" }
|
7
src/addins/postgre/MANIFEST.XML
Normal file
7
src/addins/postgre/MANIFEST.XML
Normal file
@@ -0,0 +1,7 @@
|
||||
<?xml version='1.0' encoding='UTF-8'?>
|
||||
<bundle xmlns='http://v8.1c.ru/8.2/addin/bundle' name='OPIADDIN'>
|
||||
<component os='Windows' path='AddIn_x86_windows.dll' type='native' arch='i386' />
|
||||
<component os='Windows' path='AddIn_x64_windows.dll' type='native' arch='x86_64' />
|
||||
<component os='Linux' path='AddIn_x86_linux.so' type='native' arch='i386' />
|
||||
<component os='Linux' path='AddIn_x64_linux.so' type='native' arch='x86_64' />
|
||||
</bundle>
|
69
src/addins/postgre/release.bat
vendored
Normal file
69
src/addins/postgre/release.bat
vendored
Normal file
@@ -0,0 +1,69 @@
|
||||
@echo off
|
||||
|
||||
:: Установить переменную
|
||||
set CARGO_NAME=opi_sqlite
|
||||
set LIB_NAME=OPI_SQLite
|
||||
set OPENSSL_DIR=C:\msys64\mingw64
|
||||
set OPENSSL_LIB_DIR=%OPENSSL_DIR%\lib
|
||||
set OPENSSL_INCLUDE_DIR=%OPENSSL_DIR%\include
|
||||
|
||||
|
||||
:: Перейти в директорию проекта
|
||||
cd /d "%~dp0"
|
||||
|
||||
:: Создать папку для артефактов
|
||||
set OUTPUT_DIR=artifacts
|
||||
if not exist "%OUTPUT_DIR%" mkdir "%OUTPUT_DIR%"
|
||||
|
||||
:: Сборка для x86_64-pc-windows-msvc
|
||||
cargo build --release --target x86_64-pc-windows-msvc
|
||||
if errorlevel 1 goto :error
|
||||
|
||||
:: Сборка для x86_64-unknown-linux-gnu
|
||||
cargo zigbuild --release --target x86_64-unknown-linux-gnu
|
||||
if errorlevel 1 goto :error
|
||||
|
||||
:: Сборка для i686-pc-windows-msvc
|
||||
cargo build --release --target i686-pc-windows-msvc
|
||||
if errorlevel 1 goto :error
|
||||
|
||||
:: Сборка для i686-unknown-linux-gnu
|
||||
cargo zigbuild --release --target i686-unknown-linux-gnu
|
||||
if errorlevel 1 goto :error
|
||||
|
||||
:: Копирование файлов .dll и .so
|
||||
copy /y target\x86_64-pc-windows-msvc\release\%CARGO_NAME%.dll "%OUTPUT_DIR%\AddIn_x64_windows.dll"
|
||||
if errorlevel 1 goto :error
|
||||
|
||||
copy /y target\i686-pc-windows-msvc\release\%CARGO_NAME%.dll "%OUTPUT_DIR%\AddIn_x86_windows.dll"
|
||||
if errorlevel 1 goto :error
|
||||
|
||||
copy /y target\x86_64-unknown-linux-gnu\release\lib%CARGO_NAME%.so "%OUTPUT_DIR%\AddIn_x64_linux.so"
|
||||
if errorlevel 1 goto :error
|
||||
|
||||
copy /y target\i686-unknown-linux-gnu\release\lib%CARGO_NAME%.so "%OUTPUT_DIR%\AddIn_x86_linux.so"
|
||||
if errorlevel 1 goto :error
|
||||
|
||||
copy /y MANIFEST.XML "%OUTPUT_DIR%\MANIFEST.XML"
|
||||
if errorlevel 1 goto :error
|
||||
|
||||
:: Архивация
|
||||
powershell -Command "Compress-Archive -Path '%OUTPUT_DIR%\*' -Force -DestinationPath '%LIB_NAME%.zip'"
|
||||
if errorlevel 1 goto :error
|
||||
|
||||
copy /y "%LIB_NAME%.zip" "../../ru/OInt/addins/%LIB_NAME%.zip"
|
||||
copy /y "%LIB_NAME%.zip" "../../en/OInt/addins/%LIB_NAME%.zip"
|
||||
|
||||
copy /y "%LIB_NAME%.zip" "../../ru/OPI/src/CommonTemplates/%LIB_NAME%/Template.addin"
|
||||
copy /y "%LIB_NAME%.zip" "../../en/OPI/src/CommonTemplates/%LIB_NAME%/Template.addin"
|
||||
|
||||
if exist "%OUTPUT_DIR%" (
|
||||
rmdir /S /Q "%OUTPUT_DIR%"
|
||||
)
|
||||
|
||||
@echo Build and packaging completed successfully.
|
||||
exit /b 0
|
||||
|
||||
:error
|
||||
@echo An error occurred during the build or packaging process.
|
||||
exit /b 1
|
176
src/addins/postgre/src/component/methods.rs
Normal file
176
src/addins/postgre/src/component/methods.rs
Normal file
@@ -0,0 +1,176 @@
|
||||
use postgres::types::{ToSql};
|
||||
use serde_json::{Value, json, Map};
|
||||
use serde_postgres::from_row;
|
||||
use base64::{engine::general_purpose, Engine as _};
|
||||
use serde_json::Value::Null;
|
||||
use crate::component::AddIn;
|
||||
use std::collections::HashMap;
|
||||
use std::net::IpAddr;
|
||||
use std::time::{SystemTime, UNIX_EPOCH};
|
||||
|
||||
pub fn execute_query(
|
||||
add_in: &mut AddIn,
|
||||
query: String,
|
||||
params_json: String,
|
||||
force_result: bool,
|
||||
) -> String {
|
||||
|
||||
let mut client = match add_in.get_connection() {
|
||||
Some(c) => c,
|
||||
None => return format_json_error("No connection initialized"),
|
||||
};
|
||||
|
||||
// Парсинг JSON параметров
|
||||
let params: Vec<Value> = match serde_json::from_str(¶ms_json) {
|
||||
Ok(params) => params,
|
||||
Err(e) => return format_json_error(&e.to_string()),
|
||||
};
|
||||
|
||||
let params_ref = match process_params(¶ms){
|
||||
Ok(params) => params.iter().map(|param| param.as_ref()).collect::<Vec<&(dyn ToSql + Sync)>>(),
|
||||
Err(e) => return format_json_error(&e.to_string()),
|
||||
};
|
||||
|
||||
if query.trim_start().to_uppercase().starts_with("SELECT") || force_result {
|
||||
match client.query(&query, ¶ms_ref) {
|
||||
Ok(rows) => {
|
||||
let mut result = Vec::new();
|
||||
for row in rows {
|
||||
let row_json = match from_row(&row){
|
||||
Ok(row_json) => row_json,
|
||||
Err(e) => return format_json_error(&e.to_string()),
|
||||
};
|
||||
result.push(row_json);
|
||||
}
|
||||
json!({"result": true, "rows": result}).to_string()
|
||||
}
|
||||
Err(e) => format_json_error(&e.to_string()),
|
||||
}
|
||||
} else {
|
||||
match client.execute(&query, ¶ms_ref) {
|
||||
Ok(_) => json!({"result": true}).to_string(),
|
||||
Err(e) => format_json_error(&e.to_string()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn process_object(object: &Map<String, Value>) -> Result<Box<dyn ToSql + Sync>, String> {
|
||||
if object.len() != 1 {
|
||||
return Err("Object must have exactly one key-value pair specifying the type and value".to_string());
|
||||
}
|
||||
|
||||
let (key, value) = object.iter().next().unwrap();
|
||||
match key.as_str() {
|
||||
"BOOL" => value
|
||||
.as_bool()
|
||||
.map(|v| Box::new(v) as Box<dyn ToSql + Sync>)
|
||||
.ok_or_else(|| "Invalid value for BOOL".to_string()),
|
||||
"\"char\"" => value
|
||||
.as_i64()
|
||||
.and_then(|v| i8::try_from(v).ok())
|
||||
.map(|v| Box::new(v) as Box<dyn ToSql + Sync>)
|
||||
.ok_or_else(|| "Invalid value for \"char\"".to_string()),
|
||||
"SMALLINT" | "SMALLSERIAL" => value
|
||||
.as_i64()
|
||||
.and_then(|v| i16::try_from(v).ok())
|
||||
.map(|v| Box::new(v) as Box<dyn ToSql + Sync>)
|
||||
.ok_or_else(|| format!("Invalid value for {}", key)),
|
||||
"INT" | "SERIAL" => value
|
||||
.as_i64()
|
||||
.and_then(|v| i32::try_from(v).ok())
|
||||
.map(|v| Box::new(v) as Box<dyn ToSql + Sync>)
|
||||
.ok_or_else(|| format!("Invalid value for {}", key)),
|
||||
"OID" => value
|
||||
.as_u64()
|
||||
.and_then(|v| u32::try_from(v).ok())
|
||||
.map(|v| Box::new(v) as Box<dyn ToSql + Sync>)
|
||||
.ok_or_else(|| "Invalid value for OID".to_string()),
|
||||
"BIGINT" | "BIGSERIAL" => value
|
||||
.as_i64()
|
||||
.map(|v| Box::new(v) as Box<dyn ToSql + Sync>)
|
||||
.ok_or_else(|| format!("Invalid value for {}", key)),
|
||||
"REAL" => value
|
||||
.as_f64()
|
||||
.map(|v| v as f32) // Преобразование f64 в f32
|
||||
.map(|v| Box::new(v) as Box<dyn ToSql + Sync>)
|
||||
.ok_or_else(|| "Invalid value for REAL".to_string()),
|
||||
"DOUBLE PRECISION" => value
|
||||
.as_f64()
|
||||
.map(|v| Box::new(v) as Box<dyn ToSql + Sync>)
|
||||
.ok_or_else(|| "Invalid value for DOUBLE PRECISION".to_string()),
|
||||
"VARCHAR" | "TEXT" | "CHAR" | "CITEXT" | "NAME" | "LTREE" | "LQUERY" | "LTXTQUERY" => value
|
||||
.as_str()
|
||||
.map(|v| Box::new(v.to_string()) as Box<dyn ToSql + Sync>)
|
||||
.ok_or_else(|| format!("Invalid value for {}", key)),
|
||||
"BYTEA" => value
|
||||
.as_str()
|
||||
.map(|blob_str| {
|
||||
// Очистка строки base64 от лишних символов
|
||||
let cleaned_base64 = blob_str.replace(&['\n', '\r', ' '][..], "");
|
||||
general_purpose::STANDARD.decode(&cleaned_base64)
|
||||
})
|
||||
.and_then(|res| res.ok())
|
||||
.map(|v| Box::new(v) as Box<dyn ToSql + Sync>)
|
||||
.ok_or_else(|| "Invalid base64 value for BYTEA".to_string()),
|
||||
"HSTORE" => value
|
||||
.as_object()
|
||||
.map(|obj| {
|
||||
let mut map = HashMap::new();
|
||||
for (k, v) in obj.iter() {
|
||||
map.insert(
|
||||
k.clone(),
|
||||
v.as_str().map(String::from), // Значение может быть None
|
||||
);
|
||||
}
|
||||
Box::new(map) as Box<dyn ToSql + Sync>
|
||||
})
|
||||
.ok_or_else(|| "Invalid object for HSTORE".to_string()),
|
||||
"TIMESTAMP" | "TIMESTAMP WITH TIME ZONE" => value
|
||||
.as_i64()
|
||||
.map(|v| {
|
||||
let duration = UNIX_EPOCH + std::time::Duration::from_secs(v as u64);
|
||||
let system_time = SystemTime::from(duration);
|
||||
Box::new(system_time) as Box<dyn ToSql + Sync>
|
||||
})
|
||||
.ok_or_else(|| "Invalid value for TIMESTAMP".to_string()),
|
||||
"INET" => value
|
||||
.as_str()
|
||||
.and_then(|s| s.parse::<IpAddr>().ok())
|
||||
.map(|ip| Box::new(ip) as Box<dyn ToSql + Sync>)
|
||||
.ok_or_else(|| "Invalid value for INET".to_string()),
|
||||
_ => Err(format!("Unsupported type: {}", key)),
|
||||
}
|
||||
}
|
||||
|
||||
/// Конвертирует JSON-параметры в Postgres-совместимые типы
|
||||
fn process_params(params: &Vec<Value>) -> Result<Vec<Box<dyn ToSql + Sync>>, String> {
|
||||
let mut result = Vec::new();
|
||||
for param in params {
|
||||
let processed: Box<dyn ToSql + Sync> = match param {
|
||||
Value::Null => Box::new(Option::<i32>::None),
|
||||
Value::Bool(b) => Box::new(*b),
|
||||
Value::Number(n) => {
|
||||
if let Some(i) = n.as_i64() {
|
||||
Box::new(i)
|
||||
} else if let Some(f) = n.as_f64() {
|
||||
Box::new(f)
|
||||
} else {
|
||||
return Err("Invalid number".to_string());
|
||||
}
|
||||
}
|
||||
Value::String(s) => Box::new(s.clone()),
|
||||
Value::Object(obj) => process_object(obj)?,
|
||||
_ => return Err("Unsupported parameter type".to_string()),
|
||||
};
|
||||
result.push(processed);
|
||||
}
|
||||
Ok(result)
|
||||
}
|
||||
|
||||
fn format_json_error(error: &str) -> String {
|
||||
json!({
|
||||
"result": false,
|
||||
"error": error
|
||||
})
|
||||
.to_string()
|
||||
}
|
118
src/addins/postgre/src/component/mod.rs
Normal file
118
src/addins/postgre/src/component/mod.rs
Normal file
@@ -0,0 +1,118 @@
|
||||
mod methods;
|
||||
|
||||
use addin1c::{name, Variant};
|
||||
use crate::core::getset;
|
||||
use postgres::{Client, NoTls};
|
||||
use serde_json::json;
|
||||
|
||||
// МЕТОДЫ КОМПОНЕНТЫ -------------------------------------------------------------------------------
|
||||
|
||||
// Синонимы
|
||||
pub const METHODS: &[&[u16]] = &[
|
||||
name!("Connect"),
|
||||
name!("Close"),
|
||||
name!("Execute"),
|
||||
|
||||
];
|
||||
|
||||
// Число параметров функций компоненты
|
||||
pub fn get_params_amount(num: usize) -> usize {
|
||||
match num {
|
||||
0 => 0,
|
||||
1 => 0,
|
||||
2 => 3,
|
||||
_ => 0,
|
||||
}
|
||||
}
|
||||
|
||||
// Соответствие функций Rust функциям компоненты
|
||||
// Вызовы должны быть обернуты в Box::new
|
||||
pub fn cal_func(obj: &mut AddIn, num: usize, params: &mut [Variant]) -> Box<dyn getset::ValueType> {
|
||||
|
||||
match num {
|
||||
|
||||
0 => Box::new(obj.initialize()),
|
||||
1 => Box::new(obj.close_connection()),
|
||||
2 => {
|
||||
|
||||
let query = params[0].get_string().unwrap_or("".to_string());
|
||||
let params_json = params[1].get_string().unwrap_or("".to_string());
|
||||
let force_result = params[2].get_bool().unwrap_or(false);
|
||||
|
||||
Box::new(methods::execute_query(obj, query, params_json, force_result))
|
||||
},
|
||||
_ => Box::new(false), // Неверный номер команды
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------------------------------
|
||||
|
||||
// ПОЛЯ КОМПОНЕНТЫ ---------------------------------------------------------------------------------
|
||||
|
||||
// Синонимы
|
||||
pub const PROPS: &[&[u16]] = &[
|
||||
name!("Database")
|
||||
];
|
||||
|
||||
|
||||
pub struct AddIn {
|
||||
connection_string: String,
|
||||
client: Option<Client>,
|
||||
}
|
||||
|
||||
impl AddIn {
|
||||
/// Создает новый объект
|
||||
pub fn new() -> Self {
|
||||
AddIn {
|
||||
connection_string: String::new(),
|
||||
client: None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn initialize(&mut self) -> String {
|
||||
match Client::connect(&self.connection_string, NoTls) {
|
||||
Ok(client) => {
|
||||
self.client = Some(client);
|
||||
json!({"result": true}).to_string()
|
||||
}
|
||||
Err(e) => json!({
|
||||
"result": false,
|
||||
"error": e.to_string()
|
||||
})
|
||||
.to_string(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_connection(&self) -> Option<&Client> {
|
||||
self.client.as_ref()
|
||||
}
|
||||
|
||||
pub fn close_connection(&mut self) -> String {
|
||||
if self.client.take().is_some() {
|
||||
json!({"result": true}).to_string()
|
||||
} else {
|
||||
json!({
|
||||
"result": false,
|
||||
"error": "Connection already closed"
|
||||
})
|
||||
.to_string()
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_field_ptr(&self, index: usize) -> *const dyn getset::ValueType {
|
||||
match index {
|
||||
0 => &self.connection_string as &dyn getset::ValueType as *const _,
|
||||
_ => panic!("Index out of bounds"),
|
||||
}
|
||||
}
|
||||
pub fn get_field_ptr_mut(&mut self, index: usize) -> *mut dyn getset::ValueType { self.get_field_ptr(index) as *mut _ }
|
||||
}
|
||||
// -------------------------------------------------------------------------------------------------
|
||||
|
||||
// УНИЧТОЖЕНИЕ ОБЪЕКТА -----------------------------------------------------------------------------
|
||||
|
||||
// Обработка удаления объекта
|
||||
impl Drop for AddIn {
|
||||
fn drop(&mut self) {}
|
||||
}
|
78
src/addins/postgre/src/core/getset.rs
Normal file
78
src/addins/postgre/src/core/getset.rs
Normal file
@@ -0,0 +1,78 @@
|
||||
use addin1c::{Variant, Tm};
|
||||
|
||||
|
||||
pub trait ValueType {
|
||||
fn get_value(&self, val: &mut Variant) -> bool;
|
||||
fn set_value(&mut self, val: &Variant);
|
||||
}
|
||||
|
||||
// Реализация для i32
|
||||
impl ValueType for i32 {
|
||||
fn get_value(&self, val: &mut Variant) -> bool {
|
||||
val.set_i32(*self);
|
||||
true
|
||||
}
|
||||
|
||||
fn set_value(&mut self, val: &Variant) {
|
||||
*self = val.get_i32().unwrap_or(0);
|
||||
}
|
||||
}
|
||||
|
||||
// Реализация для f64
|
||||
impl ValueType for f64 {
|
||||
fn get_value(&self, val: &mut Variant) -> bool {
|
||||
val.set_f64(*self);
|
||||
true
|
||||
}
|
||||
|
||||
fn set_value(&mut self, val: &Variant) {
|
||||
*self = val.get_f64().unwrap_or(0.0);
|
||||
}
|
||||
}
|
||||
|
||||
// Реализация для bool
|
||||
impl ValueType for bool {
|
||||
fn get_value(&self, val: &mut Variant) -> bool {
|
||||
val.set_bool(*self);
|
||||
true
|
||||
}
|
||||
|
||||
fn set_value(&mut self, val: &Variant) {
|
||||
*self = val.get_bool().unwrap_or(false);
|
||||
}
|
||||
}
|
||||
|
||||
// Реализация для tm
|
||||
impl ValueType for Tm {
|
||||
fn get_value(&self, val: &mut Variant) -> bool {
|
||||
val.set_date(*self);
|
||||
true
|
||||
}
|
||||
|
||||
fn set_value(&mut self, val: &Variant) {
|
||||
*self = val.get_date().unwrap_or(Tm::default());
|
||||
}
|
||||
}
|
||||
|
||||
// Реализация для String
|
||||
impl ValueType for String {
|
||||
fn get_value(&self, val: &mut Variant) -> bool {
|
||||
let s: Vec<u16> = self.encode_utf16().collect();
|
||||
val.set_str1c(s.as_slice()).is_ok()
|
||||
}
|
||||
|
||||
fn set_value(&mut self, val: &Variant) {
|
||||
*self = val.get_string().unwrap_or("".to_string());
|
||||
}
|
||||
}
|
||||
|
||||
// Реализация для Vec<u8>
|
||||
impl ValueType for Vec<u8> {
|
||||
fn get_value(&self, val: &mut Variant) -> bool {
|
||||
val.set_blob(self.as_slice()).is_ok()
|
||||
}
|
||||
|
||||
fn set_value(&mut self, val: &Variant) {
|
||||
*self = val.get_blob().unwrap_or(&[]).to_vec()
|
||||
}
|
||||
}
|
53
src/addins/postgre/src/core/mod.rs
Normal file
53
src/addins/postgre/src/core/mod.rs
Normal file
@@ -0,0 +1,53 @@
|
||||
pub mod getset;
|
||||
|
||||
use addin1c::{name, RawAddin, Variant};
|
||||
|
||||
use crate::component::METHODS;
|
||||
use crate::component::PROPS;
|
||||
use crate::component::get_params_amount;
|
||||
use crate::component::cal_func;
|
||||
use crate::component::AddIn;
|
||||
|
||||
// Определение класса
|
||||
impl RawAddin for AddIn {
|
||||
|
||||
fn register_extension_as(&mut self) -> &'static [u16] {
|
||||
name!("Main")
|
||||
}
|
||||
fn get_n_props(&mut self) -> usize {
|
||||
PROPS.len()
|
||||
}
|
||||
fn find_prop(&mut self, name: &[u16]) -> Option<usize> {
|
||||
PROPS.iter().position(|&x| x == name)
|
||||
}
|
||||
fn get_prop_name(&mut self, num: usize, _alias: usize) -> Option<&'static [u16]> { PROPS.get(num).copied() }
|
||||
fn get_prop_val(&mut self, num: usize, val: &mut Variant) -> bool {let field: &dyn getset::ValueType = &self[num]; field.get_value(val) }
|
||||
fn set_prop_val(&mut self, num: usize, val: &Variant) -> bool {let field: &mut dyn getset::ValueType = &mut self[num]; field.set_value(val); true }
|
||||
fn is_prop_readable(&mut self, _num: usize) -> bool { true }
|
||||
fn is_prop_writable(&mut self, _num: usize) -> bool { true }
|
||||
fn get_n_methods(&mut self) -> usize { METHODS.len() }
|
||||
fn find_method(&mut self, name: &[u16]) -> Option<usize> { METHODS.iter().position(|&x| x == name) }
|
||||
fn get_method_name(&mut self, num: usize, _alias: usize) -> Option<&'static [u16]> { METHODS.get(num).copied() }
|
||||
fn get_n_params(&mut self, num: usize) -> usize { get_params_amount(num) }
|
||||
fn get_param_def_value(&mut self, _method_num: usize, _param_num: usize, _value: Variant, ) -> bool { true }
|
||||
fn has_ret_val(&mut self, _num: usize) -> bool { true }
|
||||
fn call_as_proc(&mut self, _num: usize, _params: &mut [Variant]) -> bool { false }
|
||||
fn call_as_func(&mut self, num: usize, params: &mut [Variant], ret_value: &mut Variant, ) -> bool { cal_func(self, num, params).get_value(ret_value) }
|
||||
|
||||
}
|
||||
|
||||
impl std::ops::Index<usize> for AddIn {
|
||||
type Output = dyn getset::ValueType;
|
||||
|
||||
fn index(&self, index: usize) -> &Self::Output {
|
||||
unsafe { &*self.get_field_ptr(index) }
|
||||
}
|
||||
}
|
||||
|
||||
impl std::ops::IndexMut<usize> for AddIn {
|
||||
fn index_mut(&mut self, index: usize) -> &mut Self::Output {
|
||||
unsafe { &mut *self.get_field_ptr_mut(index) }
|
||||
}
|
||||
}
|
||||
|
||||
|
49
src/addins/postgre/src/lib.rs
Normal file
49
src/addins/postgre/src/lib.rs
Normal file
@@ -0,0 +1,49 @@
|
||||
pub mod component;
|
||||
mod core;
|
||||
|
||||
|
||||
use std::{
|
||||
ffi::{c_int, c_long, c_void},
|
||||
sync::atomic::{AtomicI32, Ordering},
|
||||
};
|
||||
|
||||
use component::AddIn;
|
||||
use addin1c::{create_component, destroy_component, name, AttachType};
|
||||
|
||||
pub static mut PLATFORM_CAPABILITIES: AtomicI32 = AtomicI32::new(-1);
|
||||
|
||||
#[allow(non_snake_case)]
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn GetClassObject(_name: *const u16, component: *mut *mut c_void) -> c_long {
|
||||
|
||||
let addin = AddIn::new();
|
||||
create_component(component, addin)
|
||||
|
||||
}
|
||||
|
||||
#[allow(non_snake_case)]
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn DestroyObject(component: *mut *mut c_void) -> c_long {
|
||||
destroy_component(component)
|
||||
}
|
||||
|
||||
#[allow(non_snake_case)]
|
||||
#[no_mangle]
|
||||
pub extern "C" fn GetClassNames() -> *const u16 {
|
||||
// small strings for performance
|
||||
name!("Main").as_ptr()
|
||||
}
|
||||
|
||||
#[allow(non_snake_case)]
|
||||
#[no_mangle]
|
||||
#[allow(static_mut_refs)]
|
||||
pub unsafe extern "C" fn SetPlatformCapabilities(capabilities: c_int) -> c_int {
|
||||
PLATFORM_CAPABILITIES.store(capabilities, Ordering::Relaxed);
|
||||
3
|
||||
}
|
||||
|
||||
#[allow(non_snake_case)]
|
||||
#[no_mangle]
|
||||
pub extern "C" fn GetAttachType() -> AttachType {
|
||||
AttachType::Any
|
||||
}
|
Reference in New Issue
Block a user