mirror of
https://github.com/odriverobotics/ODrive.git
synced 2026-09-23 00:59:54 +08:00
attempt at optimizing (535'000 -> 522'268 B)
This commit is contained in:
@@ -234,11 +234,12 @@ void ASCII_protocol_process_line(const uint8_t* buffer, size_t len, StreamSink&
|
||||
respond(response_channel, use_checksum, "invalid command format");
|
||||
} else {
|
||||
Introspectable property = root_obj.get_child(name, sizeof(name));
|
||||
if (!property.is_valid()) {
|
||||
const StringConvertibleTypeInfo* type_info = dynamic_cast<const StringConvertibleTypeInfo*>(property.get_type_info());
|
||||
if (!type_info) {
|
||||
respond(response_channel, use_checksum, "invalid property");
|
||||
} else {
|
||||
char response[10];
|
||||
bool success = property.get_string(response, sizeof(response));
|
||||
bool success = type_info->get_string(property, response, sizeof(response));
|
||||
if (!success)
|
||||
respond(response_channel, use_checksum, "not implemented");
|
||||
else
|
||||
@@ -254,10 +255,11 @@ void ASCII_protocol_process_line(const uint8_t* buffer, size_t len, StreamSink&
|
||||
respond(response_channel, use_checksum, "invalid command format");
|
||||
} else {
|
||||
Introspectable property = root_obj.get_child(name, sizeof(name));
|
||||
if (!property.is_valid()) {
|
||||
const StringConvertibleTypeInfo* type_info = dynamic_cast<const StringConvertibleTypeInfo*>(property.get_type_info());
|
||||
if (!type_info) {
|
||||
respond(response_channel, use_checksum, "invalid property");
|
||||
} else {
|
||||
bool success = property.set_string(value, sizeof(value));
|
||||
bool success = type_info->set_string(property, value, sizeof(value));
|
||||
if (!success)
|
||||
respond(response_channel, use_checksum, "not implemented");
|
||||
}
|
||||
|
||||
@@ -15,6 +15,9 @@
|
||||
|
||||
#include <fibre/introspection.hpp>
|
||||
|
||||
#pragma GCC push_options
|
||||
#pragma GCC optimize ("s")
|
||||
|
||||
namespace fibre {
|
||||
|
||||
const unsigned char embedded_json[] = [[embedded_endpoint_definitions | to_c_string]];
|
||||
@@ -22,16 +25,36 @@ const size_t embedded_json_length = sizeof(embedded_json) - 1;
|
||||
const uint16_t json_crc_ = calc_crc16<CANONICAL_CRC16_POLYNOMIAL>(PROTOCOL_VERSION, embedded_json, embedded_json_length);
|
||||
const uint32_t json_version_id_ = (json_crc_ << 16) | calc_crc16<CANONICAL_CRC16_POLYNOMIAL>(json_crc_, embedded_json, embedded_json_length);
|
||||
|
||||
Introspectable get_property(size_t idx) {
|
||||
switch (idx) {
|
||||
[%- for endpoint in endpoints %]
|
||||
[%- if endpoint.function.name == 'exchange' and endpoint.in_bindings | list == ['obj'] %]
|
||||
case [[endpoint.id]]: return FibrePropertyTypeInfo<[[endpoint.function.in['obj'].type.c_type]]>::make_introspectable([[endpoint.in_bindings['obj']]]);
|
||||
[%- endif %]
|
||||
[%- endfor %]
|
||||
default: return {};
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Note: with -Og this function reserves a huge amount of stack space because it
|
||||
// reserves separate space for the stack frame of each of the inlined functions.
|
||||
// The minimum known set of flags to prevent this is `-O1 -fipa-sra`.
|
||||
// `-O2` is a superset of this so that's what we use here.
|
||||
bool endpoint_handler(int idx, cbufptr_t* input_buffer, bufptr_t* output_buffer) __attribute__ ((optimize(2)));
|
||||
//bool endpoint_handler(int idx, cbufptr_t* input_buffer, bufptr_t* output_buffer) __attribute__ ((optimize(2)));
|
||||
|
||||
bool endpoint_handler(int idx, cbufptr_t* input_buffer, bufptr_t* output_buffer) {
|
||||
//Introspectable property = get_property(idx);
|
||||
//if property.is_valid()
|
||||
|
||||
switch (idx) {
|
||||
[%- for endpoint in endpoints %]
|
||||
[%- if (endpoint.function.name == 'exchange' or endpoint.function.name == 'read') and endpoint.in_bindings | list == ['obj'] %]
|
||||
//case [[endpoint.id]]: return FibrePropertyTypeInfo<[[endpoint.function.in['obj'].type.c_type]]>::make_introspectable([[endpoint.in_bindings['obj']]]);
|
||||
case [[endpoint.id]]: { return [[endpoint.function.fullname | to_snake_case]]([% for k, arg in endpoint.function.in.items() %][% if k in endpoint.in_bindings %]static_cast<[[arg.type.c_type]]>([[endpoint.in_bindings[k]]])[% else %]std::nullopt[% endif %], [% endfor %][% for k, arg in endpoint.function.out.items() %][% if k in endpoint.out_bindings %]static_cast<[[arg.type.c_type]]*>([[endpoint.out_bindings[k]]])[% else %]nullptr[% endif %], [% endfor %]input_buffer, output_buffer); } break;
|
||||
[%- else %]
|
||||
case [[endpoint.id]]: { return [[endpoint.function.fullname | to_snake_case]]([% for k, arg in endpoint.function.in.items() %][% if k in endpoint.in_bindings %]static_cast<[[arg.type.c_type]]>([[endpoint.in_bindings[k]]])[% else %]std::nullopt[% endif %], [% endfor %][% for k, arg in endpoint.function.out.items() %][% if k in endpoint.out_bindings %]static_cast<[[arg.type.c_type]]*>([[endpoint.out_bindings[k]]])[% else %]nullptr[% endif %], [% endfor %]input_buffer, output_buffer); } break;
|
||||
[%- endif %]
|
||||
[%- endfor %]
|
||||
default: return false;
|
||||
}
|
||||
@@ -50,17 +73,6 @@ bool is_endpoint_ref_valid(endpoint_ref_t endpoint_ref) {
|
||||
}
|
||||
}
|
||||
|
||||
Introspectable get_property(size_t idx) {
|
||||
switch (idx) {
|
||||
[%- for endpoint in endpoints %]
|
||||
[%- if endpoint.function.name == 'exchange' and endpoint.in_bindings | list == ['obj'] %][# //case [[endpoint.id]]: *(decltype([[endpoint.in_bindings['obj']]])*)buf = [[endpoint.in_bindings['obj']]]; break;#]
|
||||
case [[endpoint.id]]: return FibrePropertyTypeInfo<[[endpoint.function.in['obj'].type.c_type]]>::make_introspectable([[endpoint.in_bindings['obj']]]);
|
||||
[%- endif %]
|
||||
[%- endfor %]
|
||||
default: return {};
|
||||
}
|
||||
}
|
||||
|
||||
bool set_endpoint_from_float(endpoint_ref_t endpoint_ref, float value) {
|
||||
if (endpoint_ref.json_crc != json_crc_) {
|
||||
return false;
|
||||
@@ -73,4 +85,6 @@ bool set_endpoint_from_float(endpoint_ref_t endpoint_ref, float value) {
|
||||
|
||||
}
|
||||
|
||||
#pragma GCC pop_options
|
||||
|
||||
#endif // __FIBRE_INTERFACES_HPP
|
||||
@@ -5,12 +5,15 @@
|
||||
#include <algorithm>
|
||||
#include <cstring>
|
||||
|
||||
#pragma GCC push_options
|
||||
#pragma GCC optimize ("s")
|
||||
|
||||
class TypeInfo;
|
||||
class Introspectable;
|
||||
using introspectable_storage_t = std::aligned_storage<16, 4>::type;
|
||||
|
||||
struct PropertyInfo {
|
||||
const char * name;
|
||||
void(*getter)(Introspectable&);
|
||||
const TypeInfo* type_info;
|
||||
};
|
||||
|
||||
@@ -29,24 +32,16 @@ public:
|
||||
TypeInfo(const PropertyInfo* property_table, size_t property_table_length)
|
||||
: property_table_(property_table), property_table_length_(property_table_length) {}
|
||||
|
||||
const PropertyInfo* get_property_info(const char * name, size_t length) const {
|
||||
for (const PropertyInfo* prop = property_table_; prop < (property_table_ + property_table_length_); ++prop) {
|
||||
if (!strncmp(name, prop->name, length)) {
|
||||
return prop;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
virtual introspectable_storage_t get_child(introspectable_storage_t obj, size_t idx) const = 0;
|
||||
Introspectable get_child(const Introspectable& obj, const char * name, size_t length) const;
|
||||
|
||||
protected:
|
||||
|
||||
template<typename T> static T& as(Introspectable& obj);
|
||||
template<typename T> static const T& as(const Introspectable& obj);
|
||||
template<typename T> static Introspectable make_introspectable(T obj, const TypeInfo* type_info);
|
||||
|
||||
private:
|
||||
virtual bool get_string(const Introspectable& obj, char* buffer, size_t length) const { return false; }
|
||||
virtual bool set_string(const Introspectable& obj, char* buffer, size_t length) const { return false; }
|
||||
|
||||
const PropertyInfo* property_table_;
|
||||
size_t property_table_length_;
|
||||
};
|
||||
@@ -83,13 +78,7 @@ public:
|
||||
|
||||
while ((begin < end) && current.type_info_) {
|
||||
const char * end_of_token = std::find(begin, end, '.');
|
||||
const PropertyInfo* prop_info = current.type_info_->get_property_info(begin, end_of_token - begin);
|
||||
if (prop_info) {
|
||||
(*prop_info->getter)(current);
|
||||
current.type_info_ = prop_info->type_info;
|
||||
} else {
|
||||
current.type_info_ = nullptr;
|
||||
}
|
||||
current = current.get_direct_child(begin, end_of_token - begin);
|
||||
begin = std::min(end, end_of_token + 1);
|
||||
}
|
||||
|
||||
@@ -100,44 +89,38 @@ public:
|
||||
return type_info_;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns the underlying value as a string. This will only succeed
|
||||
* if this Introspectable contains a Property<...> object.
|
||||
*/
|
||||
bool get_string(char* buffer, size_t length) {
|
||||
return type_info_ && type_info_->get_string(*this, buffer, length);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Sets the underlying value from a string. This will only succeed
|
||||
* if this Introspectable contains a Property<...> object.
|
||||
*/
|
||||
bool set_string(char* buffer, size_t length) {
|
||||
return type_info_ && type_info_->set_string(*this, buffer, length);
|
||||
}
|
||||
|
||||
const TypeInfo* get_type_info() {
|
||||
return type_info_;
|
||||
}
|
||||
|
||||
private:
|
||||
Introspectable get_direct_child(const char * name, size_t length) const {
|
||||
for (size_t i = 0; i < type_info_->property_table_length_; ++i) {
|
||||
if (!strncmp(name, type_info_->property_table_[i].name, length)) {
|
||||
Introspectable result;
|
||||
result.storage_ = type_info_->get_child(storage_, i);
|
||||
result.type_info_ = type_info_->property_table_[i].type_info;
|
||||
return result;
|
||||
}
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
// We use this storage to hold generic small objects. Usually that's a pointer
|
||||
// but sometimes it's an on-demand constructed Property<...>.
|
||||
// Caution: only put objects in here which are trivially copyable, movable
|
||||
// and destructible as any custom operation wouldn't be called.
|
||||
unsigned char storage_[12];
|
||||
introspectable_storage_t storage_;
|
||||
const TypeInfo* type_info_ = nullptr;
|
||||
};
|
||||
|
||||
|
||||
|
||||
template<typename T> T& TypeInfo::as(Introspectable& obj) {
|
||||
static_assert(sizeof(T) <= sizeof(obj.storage_));
|
||||
return *(T*)obj.storage_;
|
||||
return *(T*)&obj.storage_;
|
||||
}
|
||||
template<typename T> const T& TypeInfo::as(const Introspectable& obj) {
|
||||
static_assert(sizeof(T) <= sizeof(obj.storage_));
|
||||
return *(const T*)obj.storage_;
|
||||
return *(const T*)&obj.storage_;
|
||||
}
|
||||
template<typename T> Introspectable TypeInfo::make_introspectable(T obj, const TypeInfo* type_info) {
|
||||
Introspectable introspectable;
|
||||
@@ -154,8 +137,13 @@ template<typename T> struct maybe_underlying_type<T, false> { typedef T type; };
|
||||
template<typename T> using maybe_underlying_type_t = typename maybe_underlying_type<T>::type;
|
||||
|
||||
|
||||
struct StringConvertibleTypeInfo {
|
||||
virtual bool get_string(const Introspectable& obj, char* buffer, size_t length) const { return false; }
|
||||
virtual bool set_string(const Introspectable& obj, char* buffer, size_t length) const { return false; }
|
||||
};
|
||||
|
||||
struct FloatSettableTypeInfo {
|
||||
//virtual bool get_float(const Introspectable& obj, float* val) const { return false; }
|
||||
virtual bool set_float(const Introspectable& obj, float val) const { return false; }
|
||||
};
|
||||
|
||||
@@ -166,11 +154,15 @@ struct FibrePropertyTypeInfo;
|
||||
|
||||
// readonly property
|
||||
template<typename T>
|
||||
struct FibrePropertyTypeInfo<Property<const T>> : TypeInfo {
|
||||
struct FibrePropertyTypeInfo<Property<const T>> : StringConvertibleTypeInfo, TypeInfo {
|
||||
using TypeInfo::TypeInfo;
|
||||
static const PropertyInfo property_table[];
|
||||
static const FibrePropertyTypeInfo<Property<const T>> singleton;
|
||||
|
||||
introspectable_storage_t get_child(introspectable_storage_t obj, size_t idx) const override {
|
||||
return {};
|
||||
}
|
||||
|
||||
bool get_string(const Introspectable& obj, char* buffer, size_t length) const override {
|
||||
return to_string(static_cast<maybe_underlying_type_t<T>>(as<const Property<const T>>(obj).read()), buffer, length, 0);
|
||||
}
|
||||
@@ -183,12 +175,16 @@ const FibrePropertyTypeInfo<Property<const T>> FibrePropertyTypeInfo<Property<co
|
||||
|
||||
// readwrite property
|
||||
template<typename T>
|
||||
struct FibrePropertyTypeInfo<Property<T>> : FloatSettableTypeInfo, TypeInfo {
|
||||
struct FibrePropertyTypeInfo<Property<T>> : FloatSettableTypeInfo, StringConvertibleTypeInfo, TypeInfo {
|
||||
using TypeInfo::TypeInfo;
|
||||
static const PropertyInfo property_table[];
|
||||
static const FibrePropertyTypeInfo<Property<T>> singleton;
|
||||
static const Introspectable make_introspectable(Property<T> obj) { return TypeInfo::make_introspectable(obj, &singleton); }
|
||||
|
||||
introspectable_storage_t get_child(introspectable_storage_t obj, size_t idx) const override {
|
||||
return {};
|
||||
}
|
||||
|
||||
bool get_string(const Introspectable& obj, char* buffer, size_t length) const override {
|
||||
return to_string(static_cast<maybe_underlying_type_t<T>>(as<const Property<T>>(obj).read()), buffer, length, 0);
|
||||
}
|
||||
@@ -217,4 +213,6 @@ const PropertyInfo FibrePropertyTypeInfo<Property<T>>::property_table[] = {};
|
||||
template<typename T>
|
||||
const FibrePropertyTypeInfo<Property<T>> FibrePropertyTypeInfo<Property<T>>::singleton{FibrePropertyTypeInfo<Property<T>>::property_table, sizeof(FibrePropertyTypeInfo<Property<T>>::property_table) / sizeof(FibrePropertyTypeInfo<Property<T>>::property_table[0])};
|
||||
|
||||
#pragma GCC pop_options
|
||||
|
||||
#endif // __FIBRE_INTROSPECTION_HPP
|
||||
@@ -566,6 +566,8 @@ template<typename T>
|
||||
struct Property {
|
||||
Property(void* ctx, T(*getter)(void*), void(*setter)(void*, T))
|
||||
: ctx_(ctx), getter_(getter), setter_(setter) {}
|
||||
Property(T* ctx)
|
||||
: ctx_(ctx), getter_([](void* ctx){ return *(T*)ctx; }), setter_([](void* ctx, T val){ *(T*)ctx = val; }) {}
|
||||
Property& operator*() { return *this; }
|
||||
Property* operator->() { return this; }
|
||||
|
||||
@@ -590,6 +592,8 @@ template<typename T>
|
||||
struct Property<const T> {
|
||||
Property(void* ctx, T(*getter)(void*))
|
||||
: ctx_(ctx), getter_(getter) {}
|
||||
Property(const T* ctx)
|
||||
: ctx_(const_cast<T*>(ctx)), getter_([](void* ctx){ return *(const T*)ctx; }) {}
|
||||
Property& operator*() { return *this; }
|
||||
Property* operator->() { return this; }
|
||||
|
||||
|
||||
@@ -10,6 +10,9 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma GCC push_options
|
||||
#pragma GCC optimize ("s")
|
||||
|
||||
[%- macro rettype(func) %]
|
||||
[%- if not func.out -%]
|
||||
void
|
||||
@@ -36,13 +39,15 @@ public:
|
||||
|
||||
[%- for property in intf.attributes.values() %]
|
||||
[%- if property.type.fullname.startswith("fibre.Property") %]
|
||||
[%- if not property.c_setter %]
|
||||
template<typename T> static auto get_[[property.name]](T* obj) { return [[property.type.c_type]]{obj, [](void* ctx){ return ([[property.type.value_type.c_type]])((T*)ctx)->[[property.c_getter]]; }}; }
|
||||
[%- if not property.c_getter and not property.c_setter %]
|
||||
template<typename T> static inline auto get_[[property.name]](T* obj) { return [[property.type.c_type]]{&obj->[[property.c_name]]}; }
|
||||
[%- elif not property.c_setter %]
|
||||
template<typename T> static inline auto get_[[property.name]](T* obj) { return [[property.type.c_type]]{obj, [](void* ctx){ return ([[property.type.value_type.c_type]])((T*)ctx)->[[property.c_getter]]; }}; }
|
||||
[%- else %]
|
||||
template<typename T> static auto get_[[property.name]](T* obj) { return [[property.type.c_type]]{obj, [](void* ctx){ return ([[property.type.value_type.c_type]])((T*)ctx)->[[property.c_getter]]; }, [](void* ctx, [[property.type.value_type.c_type]] value){ ((T*)ctx)->[[property.c_setter]](value); }}; }
|
||||
template<typename T> static inline auto get_[[property.name]](T* obj) { return [[property.type.c_type]]{obj, [](void* ctx){ return ([[property.type.value_type.c_type]])((T*)ctx)->[[property.c_getter]]; }, [](void* ctx, [[property.type.value_type.c_type]] value){ ((T*)ctx)->[[property.c_setter]](value); }}; }
|
||||
[%- endif %]
|
||||
[%- else %]
|
||||
template<typename T> static auto get_[[property.name]](T* obj) { return &obj->[[property.c_name]]; }
|
||||
template<typename T> static inline auto get_[[property.name]](T* obj) { return &obj->[[property.c_name]]; }
|
||||
[%- endif %]
|
||||
[%- endfor %]
|
||||
|
||||
@@ -80,3 +85,5 @@ inline [[enum.c_type]] operator ~ ([[enum.c_type]] a) { return static_cast<[[enu
|
||||
[%- endfor %]
|
||||
|
||||
|
||||
|
||||
#pragma GCC pop_options
|
||||
|
||||
@@ -11,6 +11,9 @@
|
||||
|
||||
#include <fibre/introspection.hpp>
|
||||
|
||||
#pragma GCC push_options
|
||||
#pragma GCC optimize ("s")
|
||||
|
||||
[% for intf in interfaces.values() %][% if not intf.builtin %]
|
||||
template<typename T>
|
||||
struct [[intf.fullname | to_pascal_case]]TypeInfo : TypeInfo {
|
||||
@@ -18,6 +21,17 @@ struct [[intf.fullname | to_pascal_case]]TypeInfo : TypeInfo {
|
||||
static const PropertyInfo property_table[];
|
||||
static const [[intf.fullname | to_pascal_case]]TypeInfo<T> singleton;
|
||||
static Introspectable make_introspectable(T& obj) { return TypeInfo::make_introspectable(&obj, &singleton); }
|
||||
|
||||
introspectable_storage_t get_child(introspectable_storage_t obj, size_t idx) const override {
|
||||
T* ptr = *(T**)&obj;
|
||||
introspectable_storage_t res;
|
||||
switch (idx) {
|
||||
[%- for property in intf.attributes.values() %]
|
||||
case [[loop.index0]]: *(decltype([[intf.c_type]]::get_[[property.name]](std::declval<T*>()))*)(&res) = [[intf.c_type]]::get_[[property.name]](ptr); break;
|
||||
[%- endfor %]
|
||||
}
|
||||
return res;
|
||||
}
|
||||
};
|
||||
[% endif %][% endfor %]
|
||||
|
||||
@@ -25,10 +39,12 @@ struct [[intf.fullname | to_pascal_case]]TypeInfo : TypeInfo {
|
||||
template<typename T>
|
||||
const PropertyInfo [[intf.fullname | to_pascal_case]]TypeInfo<T>::property_table[] = {
|
||||
[%- for property in intf.attributes.values() %]
|
||||
{"[[property.name]]", [](Introspectable& obj){ as<std::remove_reference_t<decltype([[intf.c_type]]::get_[[property.name]](std::declval<T*>()))>>(obj) = [[intf.c_type]]::get_[[property.name]](as<T*>(obj)); }, &[[(property.type.purename or property.type.fullname) | to_pascal_case]]TypeInfo<std::remove_reference_t<decltype(*[[intf.c_type]]::get_[[property.name]](std::declval<T*>()))>>::singleton},
|
||||
{"[[property.name]]", &[[(property.type.purename or property.type.fullname) | to_pascal_case]]TypeInfo<std::remove_reference_t<decltype(*[[intf.c_type]]::get_[[property.name]](std::declval<T*>()))>>::singleton},
|
||||
[%- endfor %]
|
||||
};
|
||||
template<typename T>
|
||||
const [[intf.fullname | to_pascal_case]]TypeInfo<T> [[intf.fullname | to_pascal_case]]TypeInfo<T>::singleton{[[intf.fullname | to_pascal_case]]TypeInfo<T>::property_table, sizeof([[intf.fullname | to_pascal_case]]TypeInfo<T>::property_table) / sizeof([[intf.fullname | to_pascal_case]]TypeInfo<T>::property_table[0])};
|
||||
|
||||
[% endif %][% endfor %]
|
||||
|
||||
#pragma GCC pop_options
|
||||
|
||||
@@ -252,19 +252,20 @@ def regularize_attribute(path, name, elem, c_is_class):
|
||||
elem['fullname'] = join_name(path, name)
|
||||
elem['typeargs'] = elem.get('typeargs', {})
|
||||
elem['c_name'] = elem.get('c_name', None) or (elem['name'] + ('_' if c_is_class else ''))
|
||||
elem['c_getter'] = elem.get('c_getter', elem['c_name'])
|
||||
elem['c_setter'] = elem.get('c_setter', elem['c_name'] + ' = ')
|
||||
if ('c_getter' in elem) or ('c_setter' in elem):
|
||||
elem['c_getter'] = elem.get('c_getter', elem['c_name'])
|
||||
elem['c_setter'] = elem.get('c_setter', elem['c_name'] + ' = ')
|
||||
|
||||
if isinstance(elem['type'], str) and elem['type'].startswith('readonly '):
|
||||
elem['typeargs']['fibre.Property.mode'] = 'readonly'
|
||||
elem['typeargs']['fibre.Property.type'] = elem['type'][len('readonly '):]
|
||||
elem['type'] = 'fibre.Property'
|
||||
if elem['typeargs']['fibre.Property.mode'] == 'readonly': elem.pop('c_setter')
|
||||
if elem['typeargs']['fibre.Property.mode'] == 'readonly' and 'c_setter' in elem: elem.pop('c_setter')
|
||||
elif ('flags' in elem['type']) or ('values' in elem['type']):
|
||||
elem['typeargs']['fibre.Property.mode'] = elem['typeargs'].get('fibre.Property.mode', None) or 'readwrite'
|
||||
elem['typeargs']['fibre.Property.type'] = regularize_valuetype(path, to_pascal_case(name), elem['type'])
|
||||
elem['type'] = 'fibre.Property'
|
||||
if elem['typeargs']['fibre.Property.mode'] == 'readonly': elem.pop('c_setter')
|
||||
if elem['typeargs']['fibre.Property.mode'] == 'readonly' and 'c_setter' in elem: elem.pop('c_setter')
|
||||
else:
|
||||
elem['type'] = regularize_interface(path, to_pascal_case(name), elem['type'])
|
||||
return elem
|
||||
|
||||
Reference in New Issue
Block a user