1
0
mirror of https://github.com/medigor/example-native-api-rs.git synced 2024-11-21 17:56:37 +02:00

add simple example

This commit is contained in:
medigor 2023-10-14 21:38:39 +03:00
parent 7d8b2f500d
commit d74087af76
11 changed files with 562 additions and 156 deletions

View File

@ -7,12 +7,12 @@ edition = "2021"
crate-type = ["cdylib"]
[profile.release]
opt-level = "z" # Optimize for size.
lto = true # 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" # Optimize for size.
lto = true # 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.
[dependencies]
utf16_lit="2.0"
utf16_lit = "2.0"
smallvec = "1.11"

View File

@ -23,6 +23,9 @@
* [src/lib.rs](src/lib.rs) - корень крейта, здесь располагаются экспортные функции GetClassNames и др.
* [src/ffi.rs](src/ffi.rs) - в этом модуле всё что связано с взаимодействием, также здесь находится весь небезопасный код.
* [src/addin1.rs](src/addin1.rs) - здесь непосредственно реализация компоненты, причем весь код безопасный.
* [src/addin2.rs](src/addin2.rs) - упрощенный вариант, используется другой трейт.
* [src/easy.rs](src/easy.rs) - трейт Addin для упрощенного варианта.
* [src/macros.rs](src/macros.rs) - содержит единственный макрос `name!` для удобного задания имен свойств, методов, классов.
* [conf1c](conf1c) - конфигурация 1С (выгрузка из конфигуратора 8.3.22), минимальный тестовый код.
## Разработка
@ -55,10 +58,10 @@
"env": {"DISPLAY": ":1"}
```
Для разработки и тестирования также подходит [Учебная версия 1С](https://online.1c.ru/catalog/free/learning.php), но версия для windows только x32.
При разработке использовался rust 1.66.
При разработке использовался rust последней стабильной версии.
## Поддержка платформ
У меня в проде не используется, используйте на свой страх и риск!
У меня в проде не используется, но в тестах использовал, поблем не замечено, также производные разработки тоже успешно используются.
- Windows x64 - тестировал, работает и gnu и msvc.
- Windows x32 - тестировал, работает и gnu и msvc.
- Linux x64 - тестировал, работает.

View File

@ -1,11 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?>
<ConfigDumpInfo xmlns="http://v8.1c.ru/8.3/xcf/dumpinfo" xmlns:xen="http://v8.1c.ru/8.3/xcf/enums" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" format="Hierarchical" version="2.15">
<ConfigVersions>
<Metadata name="Configuration.Конфигурация" id="72b21170-d6cc-48ee-8426-d69353f61fd5" configVersion="c712ec3fc94b2b4182496f0827cf4bff00000000"/>
<Metadata name="Configuration.Конфигурация.HomePageWorkArea" id="29e7f5a4-dc26-408a-bd6e-083b5bf1384c.8" configVersion="33c420fc5cc12348954bd259bb0c136000000000"/>
<Metadata name="DataProcessor.Обработка1" id="33179d0b-730e-44f5-b20c-1af11f7f1f60" configVersion="86cf80c3e753094aa1ab6bbb3cce13b400000000"/>
<Metadata name="DataProcessor.Обработка1.Form.Форма" id="24033a67-5ef1-4265-9a88-eb7f279ce1cb" configVersion="b49039a0c3894b41a732cee38bfae78d00000000"/>
<Metadata name="DataProcessor.Обработка1.Form.Форма.Form" id="24033a67-5ef1-4265-9a88-eb7f279ce1cb.0" configVersion="4773009ef4f1164eadd05bc75928d86900000000"/>
<Metadata name="Language.Русский" id="e3ac9659-5250-4530-9ca6-3f4f4ef6413a" configVersion="63a64f60c307414fabfabd0d777a47cc00000000"/>
<Metadata name="Configuration.Конфигурация" id="72b21170-d6cc-48ee-8426-d69353f61fd5" configVersion="7bb3aedfabf3f347b0d90a1723e8f3c800000000"/>
<Metadata name="Configuration.Конфигурация.HomePageWorkArea" id="29e7f5a4-dc26-408a-bd6e-083b5bf1384c.8" configVersion="e07ffb9930bcfd419cc94bfed56fc39700000000"/>
<Metadata name="DataProcessor.Обработка1" id="33179d0b-730e-44f5-b20c-1af11f7f1f60" configVersion="3864a8102742ba46ac0ed9ae8552c89d00000000"/>
<Metadata name="DataProcessor.Обработка1.Form.Форма" id="24033a67-5ef1-4265-9a88-eb7f279ce1cb" configVersion="26d36b8115680a42a52b99d8b011342e00000000"/>
<Metadata name="DataProcessor.Обработка1.Form.Форма.Form" id="24033a67-5ef1-4265-9a88-eb7f279ce1cb.0" configVersion="368ad81321aa084d82a53c976986a94100000000"/>
<Metadata name="Language.Русский" id="e3ac9659-5250-4530-9ca6-3f4f4ef6413a" configVersion="9b1ab00d6dd15a48b70a736c7e6be41900000000"/>
</ConfigVersions>
</ConfigDumpInfo>

View File

@ -21,6 +21,16 @@
<CommandName>Form.Command.Тест2</CommandName>
<ExtendedTooltip name="Тест2РасширеннаяПодсказка" id="4"/>
</Button>
<Button name="Тест3" id="24">
<Type>UsualButton</Type>
<CommandName>Form.Command.Тест3</CommandName>
<ExtendedTooltip name="Тест3РасширеннаяПодсказка" id="25"/>
</Button>
<Button name="Тест4" id="26">
<Type>UsualButton</Type>
<CommandName>Form.Command.Тест4</CommandName>
<ExtendedTooltip name="Тест4РасширеннаяПодсказка" id="27"/>
</Button>
</ChildItems>
<Attributes>
<Attribute name="Объект" id="1">
@ -79,5 +89,35 @@
</ToolTip>
<Action>Тест1</Action>
</Command>
<Command name="Тест3" id="3">
<Title>
<v8:item>
<v8:lang>ru</v8:lang>
<v8:content>Тест3</v8:content>
</v8:item>
</Title>
<ToolTip>
<v8:item>
<v8:lang>ru</v8:lang>
<v8:content>Тест3</v8:content>
</v8:item>
</ToolTip>
<Action>Тест3</Action>
</Command>
<Command name="Тест4" id="4">
<Title>
<v8:item>
<v8:lang>ru</v8:lang>
<v8:content>Тест4</v8:content>
</v8:item>
</Title>
<ToolTip>
<v8:item>
<v8:lang>ru</v8:lang>
<v8:content>Тест4</v8:content>
</v8:item>
</ToolTip>
<Action>Тест4</Action>
</Command>
</Commands>
</Form>

View File

@ -91,3 +91,61 @@
Сообщить(СтрШаблон("Длительность: %1", Конец - Начало));
КонецПроцедуры
&НаКлиенте
Процедура Тест3(Команда)
Тест3НаСервере(ИмяФайла);
КонецПроцедуры
&НаСервереБезКонтекста
Процедура Тест3НаСервере(ИмяФайла)
Попытка
ОбъектКомпоненты2 = Новый ("AddIn.Test.Class2");
Исключение
Если Не ПодключитьВнешнююКомпоненту(ИмяФайла, "Test", ТипВнешнейКомпоненты.Native, ТипПодключенияВнешнейКомпоненты.НеИзолированно) Тогда
ВызватьИсключение "Не удалось подключить";
КонецЕсли;
ОбъектКомпоненты2 = Новый ("AddIn.Test.Class2");
КонецПопытки;
Если ОбъектКомпоненты2.Method1(111) <> 222 Тогда
ВызватьИсключение "Не удалось вызвать Method1";
КонецЕсли;
Если ОбъектКомпоненты2.Method2(111, 222) <> 333 Тогда
ВызватьИсключение "Не удалось вызвать Method2";
КонецЕсли;
Если ОбъектКомпоненты2.Prop1 <> 333 Тогда
ВызватьИсключение "Свойство Prop1 содержит неверное значение";
КонецЕсли;
Сообщить("Тест выполнен успешно");
КонецПроцедуры
&НаКлиенте
Процедура Тест4(Команда)
Тест4НаСервере(ИмяФайла);
КонецПроцедуры
&НаСервереБезКонтекста
Процедура Тест4НаСервере(ИмяФайла)
Попытка
ОбъектКомпоненты2 = Новый ("AddIn.Test.Class2");
Исключение
Если Не ПодключитьВнешнююКомпоненту(ИмяФайла, "Test", ТипВнешнейКомпоненты.Native, ТипПодключенияВнешнейКомпоненты.НеИзолированно) Тогда
ВызватьИсключение "Не удалось подключить";
КонецЕсли;
ОбъектКомпоненты2 = Новый ("AddIn.Test.Class2");
КонецПопытки;
Начало = ТекущаяУниверсальнаяДатаВМиллисекундах();
Для К = 1 По 1000000 Цикл
ОбъектКомпоненты2.Prop1 = 123;
КонецЦикла;
Конец = ТекущаяУниверсальнаяДатаВМиллисекундах();
Сообщить(СтрШаблон("Длительность: %1 мс", Конец - Начало));
КонецПроцедуры

View File

@ -1,17 +1,21 @@
use crate::ffi::{Addin, Connection, ParamValue, Tm, Variant};
use utf16_lit::{utf16, utf16_null};
use utf16_lit::utf16;
use crate::{
ffi::{Addin, ParamValue, Tm, Variant},
name,
};
const PROPS: &[&[u16]] = &[
&utf16_null!("Test"),
&utf16_null!("PropI32"),
&utf16_null!("PropF64"),
&utf16_null!("PropBool"),
&utf16_null!("PropDate"),
&utf16_null!("PropStr"),
&utf16_null!("PropBlob"),
name!("Test"),
name!("PropI32"),
name!("PropF64"),
name!("PropBool"),
name!("PropDate"),
name!("PropStr"),
name!("PropBlob"),
];
const METHODS: &[&[u16]] = &[&utf16_null!("Method1"), &utf16_null!("Method2")];
const METHODS: &[&[u16]] = &[name!("Method1"), name!("Method2")];
pub struct Addin1 {
test: i32,
@ -42,14 +46,8 @@ impl Drop for Addin1 {
}
impl Addin for Addin1 {
fn init(&mut self, _interface: &'static Connection) -> bool {
true
}
fn done(&mut self) {}
fn register_extension_as(&mut self) -> &'static [u16] {
&utf16_null!("Class1")
name!("Class1")
}
fn get_n_props(&mut self) -> usize {
@ -235,8 +233,4 @@ impl Addin for Addin1 {
_ => false,
}
}
fn set_locale(&mut self, _loc: &[u16]) {}
fn set_user_interface_language_code(&mut self, _lang: &[u16]) {}
}

View File

@ -1,116 +1,80 @@
use crate::ffi::{Addin, Connection, ParamValue, Variant};
use utf16_lit::utf16_null;
use crate::{
simple::{Addin, MethodInfo, Methods, PropInfo},
ffi::{ParamValue, Variant}, name,
};
pub struct Addin2 {
test1: i32,
prop1: i32,
}
impl Addin2 {
pub fn new() -> Addin2 {
Addin2 { test1: 12345 }
Addin2 { prop1: 0 }
}
}
impl Drop for Addin2 {
fn drop(&mut self) {}
fn method1(&mut self, param: &mut Variant, ret_value: &mut Variant) -> bool {
let ParamValue::I32(value) = param.get() else {
return false;
};
self.prop1 = value;
ret_value.set_i32(value * 2);
true
}
fn method2(
&mut self,
param1: &mut Variant,
param2: &mut Variant,
ret_value: &mut Variant,
) -> bool {
let ParamValue::I32(value1) = param1.get() else {
return false;
};
let ParamValue::I32(value2) = param2.get() else {
return false;
};
self.prop1 = value1 + value2;
ret_value.set_i32(self.prop1);
true
}
fn set_prop1(&mut self, value: &ParamValue) -> bool {
let ParamValue::I32(value) = value else {
return false;
};
self.prop1 = *value;
true
}
fn get_prop1(&mut self, value: &mut Variant) -> bool {
value.set_i32(self.prop1);
true
}
}
impl Addin for Addin2 {
fn init(&mut self, _interface: &'static Connection) -> bool {
true
fn name() -> &'static [u16] {
name!("Class2")
}
fn done(&mut self) {}
fn register_extension_as(&mut self) -> &'static [u16] {
&utf16_null!("Class2")
fn methods() -> &'static [MethodInfo<Self>] {
&[
MethodInfo {
name: name!("Method1"),
method: Methods::Method1(Self::method1),
},
MethodInfo {
name: name!("Method2"),
method: Methods::Method2(Self::method2),
},
]
}
fn get_n_props(&mut self) -> usize {
1
fn properties() -> &'static [PropInfo<Self>] {
&[PropInfo {
name: name!("Prop1"),
getter: Some(Self::get_prop1),
setter: Some(Self::set_prop1),
}]
}
fn find_prop(&mut self, name: &[u16]) -> Option<usize> {
const TEST1: &[u16] = &utf16_null!("Test1");
match name {
TEST1 => Some(0),
_ => None,
}
}
fn get_prop_name(&mut self, num: usize, _alias: usize) -> Option<&'static [u16]> {
if num == 0 {
Some(&utf16_null!("Test1"))
} else {
None
}
}
fn get_prop_val(&mut self, num: usize, val: &mut Variant) -> bool {
match num {
0 => {
val.set_i32(self.test1);
true
}
_ => false,
}
}
fn set_prop_val(&mut self, _num: usize, _val: &ParamValue) -> bool {
false
}
fn is_prop_readable(&mut self, _num: usize) -> bool {
true
}
fn is_prop_writable(&mut self, _num: usize) -> bool {
false
}
fn get_n_methods(&mut self) -> usize {
0
}
fn find_method(&mut self, _name: &[u16]) -> Option<usize> {
None
}
fn get_method_name(&mut self, _num: usize, _alias: usize) -> Option<&'static [u16]> {
None
}
fn get_n_params(&mut self, _num: usize) -> usize {
0
}
fn get_param_def_value(
&mut self,
_method_num: usize,
_param_num: usize,
_value: Variant,
) -> bool {
true
}
fn has_ret_val(&mut self, _method_num: usize) -> bool {
false
}
fn call_as_proc(&mut self, _method_num: usize, _params: &mut [Variant]) -> bool {
false
}
fn call_as_func(
&mut self,
_method_num: usize,
_params: &mut [Variant],
_val: &mut Variant,
) -> bool {
false
}
fn set_locale(&mut self, _loc: &[u16]) {}
fn set_user_interface_language_code(&mut self, _lang: &[u16]) {}
}

View File

@ -236,37 +236,70 @@ struct TVariant {
vt: VariantType,
}
#[allow(unused_variables)]
pub trait Addin {
fn init(&mut self, interface: &'static Connection) -> bool;
fn init(&mut self, interface: &'static Connection) -> bool {
true
}
/// default 2000, don't use version 1000, because static objects are created
fn get_info(&mut self) -> u16 {
2000
}
fn done(&mut self);
fn done(&mut self) {}
fn register_extension_as(&mut self) -> &'static [u16];
fn get_n_props(&mut self) -> usize;
fn find_prop(&mut self, name: &[u16]) -> Option<usize>;
fn get_prop_name(&mut self, num: usize, alias: usize) -> Option<&'static [u16]>;
fn get_prop_val(&mut self, num: usize, val: &mut Variant) -> bool;
fn set_prop_val(&mut self, num: usize, val: &ParamValue) -> bool;
fn is_prop_readable(&mut self, num: usize) -> bool;
fn is_prop_writable(&mut self, num: usize) -> bool;
fn get_n_methods(&mut self) -> usize;
fn find_method(&mut self, name: &[u16]) -> Option<usize>;
fn get_method_name(&mut self, num: usize, alias: usize) -> Option<&'static [u16]>;
fn get_n_params(&mut self, num: usize) -> usize;
fn get_param_def_value(&mut self, method_num: usize, param_num: usize, value: Variant) -> bool;
fn has_ret_val(&mut self, method_num: usize) -> bool;
fn call_as_proc(&mut self, method_num: usize, params: &mut [Variant]) -> bool;
fn get_n_props(&mut self) -> usize {
0
}
fn find_prop(&mut self, name: &[u16]) -> Option<usize> {
None
}
fn get_prop_name(&mut self, num: usize, alias: usize) -> Option<&'static [u16]> {
None
}
fn get_prop_val(&mut self, num: usize, val: &mut Variant) -> bool {
false
}
fn set_prop_val(&mut self, num: usize, val: &ParamValue) -> bool {
false
}
fn is_prop_readable(&mut self, num: usize) -> bool {
false
}
fn is_prop_writable(&mut self, num: usize) -> bool {
false
}
fn get_n_methods(&mut self) -> usize {
0
}
fn find_method(&mut self, name: &[u16]) -> Option<usize> {
None
}
fn get_method_name(&mut self, num: usize, alias: usize) -> Option<&'static [u16]> {
None
}
fn get_n_params(&mut self, num: usize) -> usize {
0
}
fn get_param_def_value(&mut self, method_num: usize, param_num: usize, value: Variant) -> bool {
true
}
fn has_ret_val(&mut self, method_num: usize) -> bool {
false
}
fn call_as_proc(&mut self, method_num: usize, params: &mut [Variant]) -> bool {
false
}
fn call_as_func(
&mut self,
method_num: usize,
params: &mut [Variant],
val: &mut Variant,
) -> bool;
fn set_locale(&mut self, loc: &[u16]);
fn set_user_interface_language_code(&mut self, lang: &[u16]);
) -> bool {
false
}
fn set_locale(&mut self, loc: &[u16]) {}
fn set_user_interface_language_code(&mut self, lang: &[u16]) {}
}
#[repr(C)]

View File

@ -1,6 +1,8 @@
mod addin1;
mod addin2;
mod simple;
mod ffi;
mod macros;
use std::{
ffi::{c_int, c_long, c_void},
@ -8,11 +10,10 @@ use std::{
};
use addin1::Addin1;
use ffi::{destroy_component, AttachType};
use addin2::Addin2;
use ffi::{create_component, destroy_component, AttachType};
use utf16_lit::utf16_null;
use crate::{addin2::Addin2, ffi::create_component};
pub static mut PLATFORM_CAPABILITIES: AtomicI32 = AtomicI32::new(-1);
#[allow(non_snake_case)]

7
src/macros.rs Normal file
View File

@ -0,0 +1,7 @@
/// Null terminated utf-16 static string, used for names
#[macro_export]
macro_rules! name {
($text:expr) => {
&utf16_lit::utf16_null!($text)
};
}

306
src/simple.rs Normal file
View File

@ -0,0 +1,306 @@
use crate::ffi::{self, ParamValue, Variant};
#[allow(dead_code)]
pub enum Methods<T> {
Method0(fn(&mut T, &mut Variant) -> bool),
Method1(fn(&mut T, &mut Variant, &mut Variant) -> bool),
Method2(fn(&mut T, &mut Variant, &mut Variant, &mut Variant) -> bool),
Method3(fn(&mut T, &mut Variant, &mut Variant, &mut Variant, &mut Variant) -> bool),
Method4(
fn(&mut T, &mut Variant, &mut Variant, &mut Variant, &mut Variant, &mut Variant) -> bool,
),
Method5(
fn(
&mut T,
&mut Variant,
&mut Variant,
&mut Variant,
&mut Variant,
&mut Variant,
&mut Variant,
) -> bool,
),
Method6(
fn(
&mut T,
&mut Variant,
&mut Variant,
&mut Variant,
&mut Variant,
&mut Variant,
&mut Variant,
&mut Variant,
) -> bool,
),
Method7(
fn(
&mut T,
&mut Variant,
&mut Variant,
&mut Variant,
&mut Variant,
&mut Variant,
&mut Variant,
&mut Variant,
&mut Variant,
) -> bool,
),
}
impl<T> Methods<T> {
fn params(&self) -> usize {
match self {
Methods::Method0(_) => 0,
Methods::Method1(_) => 1,
Methods::Method2(_) => 2,
Methods::Method3(_) => 3,
Methods::Method4(_) => 4,
Methods::Method5(_) => 5,
Methods::Method6(_) => 6,
Methods::Method7(_) => 7,
}
}
#[allow(unused_variables)]
fn call(&self, addin: &mut T, params: &mut [Variant], val: &mut Variant) -> bool {
match self {
Methods::Method0(f) => f(addin, val),
Methods::Method1(f) => {
let Some((p1, params)) = params.split_first_mut() else {
return false;
};
f(addin, p1, val)
}
Methods::Method2(f) => {
let Some((p1, params)) = params.split_first_mut() else {
return false;
};
let Some((p2, params)) = params.split_first_mut() else {
return false;
};
f(addin, p1, p2, val)
}
Methods::Method3(f) => {
let Some((p1, params)) = params.split_first_mut() else {
return false;
};
let Some((p2, params)) = params.split_first_mut() else {
return false;
};
let Some((p3, params)) = params.split_first_mut() else {
return false;
};
f(addin, p1, p2, p3, val)
}
Methods::Method4(f) => {
let Some((p1, params)) = params.split_first_mut() else {
return false;
};
let Some((p2, params)) = params.split_first_mut() else {
return false;
};
let Some((p3, params)) = params.split_first_mut() else {
return false;
};
let Some((p4, params)) = params.split_first_mut() else {
return false;
};
f(addin, p1, p2, p3, p4, val)
}
Methods::Method5(f) => {
let Some((p1, params)) = params.split_first_mut() else {
return false;
};
let Some((p2, params)) = params.split_first_mut() else {
return false;
};
let Some((p3, params)) = params.split_first_mut() else {
return false;
};
let Some((p4, params)) = params.split_first_mut() else {
return false;
};
let Some((p5, params)) = params.split_first_mut() else {
return false;
};
f(addin, p1, p2, p3, p4, p5, val)
}
Methods::Method6(f) => {
let Some((p1, params)) = params.split_first_mut() else {
return false;
};
let Some((p2, params)) = params.split_first_mut() else {
return false;
};
let Some((p3, params)) = params.split_first_mut() else {
return false;
};
let Some((p4, params)) = params.split_first_mut() else {
return false;
};
let Some((p5, params)) = params.split_first_mut() else {
return false;
};
let Some((p6, params)) = params.split_first_mut() else {
return false;
};
f(addin, p1, p2, p3, p4, p5, p6, val)
}
Methods::Method7(f) => {
let Some((p1, params)) = params.split_first_mut() else {
return false;
};
let Some((p2, params)) = params.split_first_mut() else {
return false;
};
let Some((p3, params)) = params.split_first_mut() else {
return false;
};
let Some((p4, params)) = params.split_first_mut() else {
return false;
};
let Some((p5, params)) = params.split_first_mut() else {
return false;
};
let Some((p6, params)) = params.split_first_mut() else {
return false;
};
let Some((p7, params)) = params.split_first_mut() else {
return false;
};
f(addin, p1, p2, p3, p4, p5, p6, p7, val)
}
}
}
}
pub struct MethodInfo<T> {
pub name: &'static [u16],
pub method: Methods<T>,
}
pub struct PropInfo<T> {
pub name: &'static [u16],
pub getter: Option<fn(&mut T, &mut Variant) -> bool>,
pub setter: Option<fn(&mut T, &ParamValue) -> bool>,
}
pub trait Addin {
fn name() -> &'static [u16];
fn get_info() -> u16 {
2000
}
fn methods() -> &'static [MethodInfo<Self>]
where
Self: Sized,
{
&[]
}
fn properties() -> &'static [PropInfo<Self>]
where
Self: Sized,
{
&[]
}
}
#[allow(unused_variables)]
impl<T: Addin + 'static> ffi::Addin for T {
fn register_extension_as(&mut self) -> &'static [u16] {
T::name()
}
fn get_info(&mut self) -> u16 {
T::get_info()
}
fn get_n_props(&mut self) -> usize {
T::properties().len()
}
fn find_prop(&mut self, name: &[u16]) -> Option<usize> {
T::properties().iter().position(|x| x.name == name)
}
fn get_prop_name(&mut self, num: usize, alias: usize) -> Option<&'static [u16]> {
T::properties().get(num).map(|x| &x.name).copied()
}
fn get_prop_val(&mut self, num: usize, val: &mut Variant) -> bool {
let Some(property) = T::properties().get(num) else {
return false;
};
let Some(getter) = property.getter else {
return false;
};
getter(self, val)
}
fn set_prop_val(&mut self, num: usize, val: &ParamValue) -> bool {
let Some(property) = T::properties().get(num) else {
return false;
};
let Some(setter) = property.setter else {
return false;
};
setter(self, val)
}
fn is_prop_readable(&mut self, num: usize) -> bool {
T::properties()[num].getter.is_some()
}
fn is_prop_writable(&mut self, num: usize) -> bool {
T::properties()[num].setter.is_some()
}
fn get_n_methods(&mut self) -> usize {
T::methods().len()
}
fn find_method(&mut self, name: &[u16]) -> Option<usize> {
T::methods().iter().position(|x| x.name == name)
}
fn get_method_name(&mut self, num: usize, alias: usize) -> Option<&'static [u16]> {
T::methods().get(num).map(|x| &x.name).copied()
}
fn get_n_params(&mut self, num: usize) -> usize {
let Some(info) = T::methods().get(num) else {
return 0;
};
info.method.params()
}
fn get_param_def_value(&mut self, method_num: usize, param_num: usize, value: Variant) -> bool {
true
}
fn has_ret_val(&mut self, method_num: usize) -> bool {
true
}
fn call_as_proc(&mut self, method_num: usize, params: &mut [Variant]) -> bool {
false
}
fn call_as_func(
&mut self,
method_num: usize,
params: &mut [Variant],
val: &mut Variant,
) -> bool {
let Some(info) = T::methods().get(method_num) else {
return false;
};
info.method.call(self, params, val)
}
}