Rust tidl generator has been supported.
It supports only version2 protocol.
Change-Id: Id6e170a90b029c45f33e5214def5409f46b6e7b0
Signed-off-by: Changgyu Choi <changyu.choi@samsung.com>
* limitations under the License.
*/
+#include <cctype>
#include <fstream>
#include <string>
namespace tidl {
Parser::Parser(bool beta_enable, bool cion_enable, bool mqtt_enable,
- bool group_enable)
+ bool group_enable, bool rust_enable)
: scanner_(nullptr), error_(false), beta_enable_(beta_enable),
cion_enable_(cion_enable), mqtt_enable_(mqtt_enable),
- group_enable_(group_enable), ver_(1) {
+ group_enable_(group_enable), rust_enable_(rust_enable),
+ ver_(1) {
yylex_init(&scanner_);
}
return group_enable_;
}
+bool Parser::IsRustEnabled() const {
+ return rust_enable_;
+}
+
+bool Parser::IsUpperCamelCase(const std::string& name) {
+ return std::isupper(name[0]);
+}
+
} // namespace tidl
class Parser {
public:
Parser(bool beta_enable = false, bool cion_enable = false,
- bool mqtt_enable = false, bool group_enable = false);
+ bool mqtt_enable = false, bool group_enable = false,
+ bool rust_enable = false);
~Parser();
void* Scanner() const { return scanner_; }
void SetDoc(Document* doc);
std::shared_ptr<Document> GetDoc() const;
void ReportError(const std::string& err, unsigned line);
+ bool IsUpperCamelCase(const std::string& name);
bool IsBetaEnabled() const;
bool IsCionEnabled() const;
+ bool IsRustEnabled() const;
bool IsMqttEnabled() const;
bool IsGroupEnabled() const;
void SetVersion(int ver);
bool cion_enable_;
bool mqtt_enable_;
bool group_enable_;
+ bool rust_enable_;
int ver_;
std::unique_ptr<Preprocessor> pr_;
};
return true;
}
+std::string GetEnumBase(const std::string& id, const Structure* st) {
+ if (st->GetEnums().Exist(id)) {
+ return st->GetID();
+ }
+
+ if (st->GetBase() != nullptr) {
+ return GetEnumBase(id, st->GetBase().get());
+ } else {
+ return "";
+ }
+}
+
} // namespace
Structure::Structure(std::string id, Elements* elms, Enums* enums,
return base_;
}
+std::string Structure::GetEnumBaseID(const std::string& id) const {
+ if (GetEnums().Exist(id))
+ return "";
+ return GetEnumBase(id, this);
+}
+
bool Structure::FindAndValidateElements() const {
for (auto& elm : GetElements()) {
if (!ValidateElement(this, elm->GetID()))
const Elements& GetElements() const;
void SetBase(std::shared_ptr<Structure> base);
const std::shared_ptr<Structure>& GetBase() const;
-
+ std::string GetEnumBaseID(const std::string& id) const;
bool FindAndValidateElements() const;
private:
start: blocks {
ps->SetDoc($1);
+ if (ps->IsRustEnabled() && ps->GetVersion() < 2) {
+ ps->ReportError("syntax error. rust is supported from protocol version 2.", 1);
+ }
}
;
;
structure_block: T_STRUCTURE T_ID T_BRACE_OPEN elements T_BRACE_CLOSE {
+ if (ps->IsRustEnabled() && !ps->IsUpperCamelCase($2->ToString())) {
+ ps->ReportError("variant `" + $2->ToString() +
+ "` should have an upper camel case name", @1.begin.line);
+ YYABORT;
+ }
+
$$ = new tidl::Structure($2->ToString(), $4, new tidl::Enums(),
$1->GetComments(), @1.begin.line);
if (!$$->FindAndValidateElements()) {
delete $2;
}
| T_STRUCTURE T_ID T_BRACE_OPEN enums elements T_BRACE_CLOSE {
+ if (ps->IsRustEnabled() && !ps->IsUpperCamelCase($2->ToString())) {
+ ps->ReportError("variant `" + $2->ToString() +
+ "` should have an upper camel case name", @1.begin.line);
+ YYABORT;
+ }
+
$$ = new tidl::Structure($2->ToString(), $5, $4, $1->GetComments(),
@1.begin.line);
if (!$$->FindAndValidateElements()) {
delete $2;
}
| T_STRUCTURE T_ID T_BRACE_OPEN enums T_BRACE_CLOSE {
+ if (ps->IsRustEnabled() && !ps->IsUpperCamelCase($2->ToString())) {
+ ps->ReportError("variant `" + $2->ToString() +
+ "` should have an upper camel case name", @1.begin.line);
+ YYABORT;
+ }
+
$$ = new tidl::Structure($2->ToString(), new tidl::Elements(), $4, $1->GetComments(),
@1.begin.line);
if (!$$->FindAndValidateElements()) {
ps->ReportError("syntax error. " + $4->ToString() + " does not exist.", @1.begin.line);
delete $6;
} else {
+ if (ps->IsRustEnabled() && !ps->IsUpperCamelCase($2->ToString())) {
+ ps->ReportError("variant `" + $2->ToString() +
+ "` should have an upper camel case name", @1.begin.line);
+ YYABORT;
+ }
+
$$ = new tidl::Structure($2->ToString(), $6, new tidl::Enums(),
$1->GetComments(), @1.begin.line);
$$->SetBase(std::dynamic_pointer_cast<tidl::Structure>(block));
delete $6;
delete $7;
} else {
+ if (ps->IsRustEnabled() && !ps->IsUpperCamelCase($2->ToString())) {
+ ps->ReportError("variant `" + $2->ToString() +
+ "` should have an upper camel case name", @1.begin.line);
+ YYABORT;
+ }
$$ = new tidl::Structure($2->ToString(), $7, $6, $1->GetComments(),
@1.begin.line);
$$->SetBase(std::dynamic_pointer_cast<tidl::Structure>(block));
ps->ReportError("syntax error. " + $4->ToString() + " does not exist.", @1.begin.line);
delete $6;
} else {
+ if (ps->IsRustEnabled() && !ps->IsUpperCamelCase($2->ToString())) {
+ ps->ReportError("variant `" + $2->ToString() +
+ "` should have an upper camel case name", @1.begin.line);
+ YYABORT;
+ }
+
$$ = new tidl::Structure($2->ToString(), new tidl::Elements(), $6, $1->GetComments(),
@1.begin.line);
$$->SetBase(std::dynamic_pointer_cast<tidl::Structure>(block));
if ($1->ToString() == "set") {
if (!tidl::BaseType::IsKeyType($3)) {
- ps->ReportError("syntax error. The key type should be 'char', 'int', 'short', 'long', 'string', 'bool', 'float' and 'double.", @1.begin.line);
+ ps->ReportError("syntax error. The key type should be 'char', 'int', 'short', 'long', 'string' and 'bool'.", @1.begin.line);
}
}
delete $1;
} else {
if (!tidl::BaseType::IsKeyType($3)) {
- ps->ReportError("syntax error. The key type should be 'char', 'int', 'short', 'long', 'string', 'bool', 'float' and 'double.", @1.begin.line);
+ ps->ReportError("syntax error. The key type should be 'char', 'int', 'short', 'long', 'string' and 'bool'.", @1.begin.line);
}
$$ = new tidl::BaseType($1->ToString(), $1->GetComments());
type->ToString() == "short" ||
type->ToString() == "string" ||
type->ToString() == "bool" ||
- type->ToString() == "float" ||
- type->ToString() == "double")
+ type->ToString() == "long")
return true;
return false;
return {};
}
+std::string Generator::PascalToSnake(const std::string& pascal_case) {
+ std::string snake_case;
+ for (int i = 0; i < pascal_case.length(); i++) {
+ if (isupper(pascal_case[i])) {
+ if (i != 0 && !isupper(pascal_case[i - 1]))
+ snake_case += "_";
+ snake_case += tolower(pascal_case[i]);
+ } else {
+ snake_case += pascal_case[i];
+ }
+ }
+ return snake_case;
+}
+
+std::string Generator::SnakeToPascal(const std::string& snake_case) {
+ std::string pascal_case;
+ bool capitalize_next = true;
+ for (char c : snake_case) {
+ if (c == '_') {
+ capitalize_next = true;
+ } else if (capitalize_next) {
+ pascal_case += toupper(c);
+ capitalize_next = false;
+ } else {
+ pascal_case += c;
+ }
+ }
+ return pascal_case;
+}
+
} // namespace tidl
virtual void OnInitGen(std::ofstream& stream) = 0;
virtual void OnFiniGen(std::ofstream& stream) = 0;
+ std::string PascalToSnake(const std::string& pascal_case);
+ std::string SnakeToPascal(const std::string& snake_case);
protected:
const Document& GetDocument() {
return *this;
}
+int ReplaceAll::GetTagStartPos(int pos) {
+ while (pos > 0 && str_[pos - 1] == ' ')
+ pos--;
+ return pos;
+}
+
+int ReplaceAll::GetTagEndPos(int pos) {
+ while (pos < str_.length() && (str_[pos] == ' ' || str_[pos] == '\n')) {
+ if (str_[pos] == '\n') {
+ pos++;
+ break;
+ }
+ pos++;
+ }
+ return pos;
+}
+
+ReplaceAll& ReplaceAll::RemoveAll(const std::string& tag, bool remove) {
+ const auto from = "<" + tag + "?>";
+ const auto to = "</" + tag + "?>";
+ std::size_t pos1 = str_.find(from, 0);
+ auto pos2 = str_.find(to, pos1);
+
+ while (pos1 != std::string::npos && pos2 != std::string::npos) {
+ auto pos1_s = GetTagStartPos(pos1);
+ auto pos1_e = GetTagEndPos(pos1 + from.length());
+ auto pos2_s = GetTagStartPos(pos2);
+ auto pos2_e = GetTagEndPos(pos2 + to.length());
+ if (!remove) {
+ str_.erase(pos2_s, pos2_e - pos2_s);
+ str_.erase(pos1_s, pos1_e - pos1_s);
+ } else {
+ str_.erase(pos1_s, pos2_e - pos1_s);
+ }
+
+ pos1 = str_.find(from, pos1);
+ pos2 = str_.find(to, pos1);
+ }
+
+ return *this;
+}
+
ReplaceAll& ReplaceAll::Remove(const std::string& tag, bool remove) {
const auto from = "<" + tag + "?>";
const auto to = "</" + tag + "?>";
if (pos1 == std::string::npos || pos2 == std::string::npos)
return *this;
+ auto pos1_s = GetTagStartPos(pos1);
+ auto pos1_e = GetTagEndPos(pos1 + from.length());
+ auto pos2_s = GetTagStartPos(pos2);
+ auto pos2_e = GetTagEndPos(pos2 + to.length());
if (!remove) {
- str_.erase(pos2, to.length());
- str_.erase(pos1, from.length());
+ str_.erase(pos2_s, pos2_e - pos2_s);
+ str_.erase(pos1_s, pos1_e - pos1_s);
} else {
- str_.erase(pos1, pos2 - pos1 + to.length());
+ str_.erase(pos1_s, pos2_e - pos1_s);
}
return *this;
});
}
-ReplaceAll& ReplaceAll::ChangeToLower(const std::string& from,
- const std::string& to) {
+ReplaceAll& ReplaceAll::ChangeToLower(const std::string &from, const std::string &to) {
return Change(from, [to]() {
std::string t = to;
std::transform(t.begin(), t.end(), t.begin(), ::tolower);
- return t;
- });
+ return t; });
}
ReplaceAll& ReplaceAll::Once(const std::string& from,
ReplaceAll& Change(const std::string& from, const std::string& to);
ReplaceAll& Remove(const std::string& tag, bool remove);
+ ReplaceAll& RemoveAll(const std::string& tag, bool remove);
ReplaceAll& Replace(const std::string& from, const std::string& to) {
return Change("<" + from + ">", to);
const auto to = "</" + tag + "*>";
auto pos1 = str_.find(from, 0);
auto pos2 = str_.find(to, pos1);
- auto pos3 = str_.rfind('\n', pos1);
- auto space = pos1 - pos3 - 1;
- std::string space_str(space, ' ');
if (pos1 == std::string::npos || pos2 == std::string::npos)
return *this;
- std::string str = str_.substr(pos1 + from.length(),
- pos2 - pos1 - from.length());
+ auto pos1_s = GetTagStartPos(pos1);
+ auto pos1_e = GetTagEndPos(pos1 + from.length());
+ auto pos2_s = GetTagStartPos(pos2);
+ auto pos2_e = GetTagEndPos(pos2 + to.length());
+ std::string str = str_.substr(pos1_e, pos2_s - pos1_e);
std::string ret;
for (const auto& i : container) {
ReplaceAll rep(str);
- if (fn(&rep, i)) {
- if (!ret.empty())
- ret += "\n" + space_str;
+ ReplaceAll& rep_ref = rep;
+ if (fn(rep_ref, i)) {
ret += rep;
}
}
- str_.replace(pos1, pos2 - pos1 + to.length(), ret);
+ str_.replace(pos1_s, pos2_e - pos1_s, ret);
+ return *this;
+ }
+
+ template <class F>
+ ReplaceAll& ReplaceBlock(const std::string& tag, F fn) {
+ const auto from = "<" + tag + "!>";
+ const auto to = "</" + tag + "!>";
+ auto pos1 = str_.find(from, 0);
+ auto pos2 = str_.find(to, pos1);
+ if (pos1 == std::string::npos || pos2 == std::string::npos)
+ return *this;
+ auto pos1_s = GetTagStartPos(pos1);
+ auto pos1_e = GetTagEndPos(pos1 + from.length());
+ auto pos2_s = GetTagStartPos(pos2);
+ auto pos2_e = GetTagEndPos(pos2 + to.length());
+ std::string str = str_.substr(pos1_e, pos2_s - pos1_e);
+ ReplaceAll rep(str);
+ ReplaceAll& rep_ref = rep;
+ fn(rep_ref);
+ str_.replace(pos1_s, pos2_e - pos1_s, rep);
return *this;
}
return Replace(from, str);
}
+ ReplaceAll& ChangeToLower(const std::string &from, const std::string &to);
ReplaceAll& ChangeToUpper(const std::string& from, const std::string& to);
- ReplaceAll& ChangeToLower(const std::string& from, const std::string& to);
+ ReplaceAll& ReplaceToUpper(const std::string& from, const std::string& to) {
+ return ChangeToUpper("<" + from + ">", to);
+ }
ReplaceAll& Once(const std::string& from, const std::string& to);
template <class T>
ReplaceAll& AddIndent(int indent, bool space = true);
void Out(std::ofstream& stream);
+ private:
+ int GetTagStartPos(int pos);
+ int GetTagEndPos(int pos);
private:
std::string str_;
};
.Change("<IMPL_SERVICE_BASE_SET_PRIVILEGE_MAP>",
GenInterfaceImplServiceBaseSetPrivilegeMap(iface))
.Repeat("IMPL_ADD_PRIVILEGE", iface.GetAttributes(),
- [&](ReplaceAll* ra,
+ [&](ReplaceAll& ra,
const std::unique_ptr<tidl::Attribute>& attr) {
if (attr->GetKey() != "privilege") return false;
- ra->Replace("PRIVILEGE", attr->GetValue());
+ ra.Replace("PRIVILEGE", attr->GetValue());
return true;
})
.Remove("IMPL_SET_TRUSTED",
--- /dev/null
+/*
+ * Copyright (c) 2024 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <sys/stat.h>
+#include <unistd.h>
+
+#include <ctime>
+#include <vector>
+
+#include "idlc/gen/version2/rs_gen_base.h"
+
+#if (defined(_WIN32) || defined(__WIN32__))
+#define mkdir(A, B) mkdir(A)
+#endif
+
+namespace tidl {
+namespace version2 {
+namespace {
+#include "idlc/gen/version2/rs_gen_base_cb.h"
+
+std::string GetBaseTypeName(const std::shared_ptr<tidl::Structure>& base) {
+ if (base->GetBase() != nullptr)
+ return GetBaseTypeName(base->GetBase()) + "::" + base->GetID();
+
+ return base->GetID();
+}
+
+void GetElementsFromStructure(Elements* elms,
+ const std::shared_ptr<Structure>& base) {
+ if (base->GetBase() != nullptr)
+ GetElementsFromStructure(elms, base->GetBase());
+
+ for (auto elm : base->GetElements())
+ elms->Add(elm);
+}
+
+Elements GetElements(const Structure& st) {
+ Elements elms;
+ if (st.GetBase() != nullptr)
+ GetElementsFromStructure(&elms, st.GetBase());
+
+ for (auto elm : st.GetElements())
+ elms.Add(elm);
+
+ return elms;
+}
+
+} //namespace
+
+RsGeneratorBase::RsGeneratorBase(std::shared_ptr<Document> doc)
+ : Generator(doc) {
+ type_map_ = {
+ {"char", "i8"}, {"int", "i32"}, {"short", "i16"},
+ {"long", "i64"}, {"string", "String"}, {"bool", "bool"},
+ {"list", "LinkedList"}, {"array", "Vec"}, {"float", "f32"},
+ {"double", "f64"}, {"bundle", "Bundle"}, {"void", "()"},
+ {"file", "String"}, {"map", "HashMap"}, {"set", "HashSet"}
+ };
+
+ parcel_type_map_ = {
+ {"char", "byte"},
+ {"int", "int32"},
+ {"short", "int16"},
+ {"long", "int64"},
+ {"string", "string"},
+ {"bool", "bool"},
+ {"float", "float"},
+ {"double", "double"},
+ {"bundle", "bundle"},
+ {"file", "string"},
+ };
+
+ type_init_map_ = {
+ {"char", "0"},
+ {"int", "0"},
+ {"short", "0"},
+ {"long", "0"},
+ {"bool", "false"},
+ {"float", "0.0f"},
+ {"double", "0.0"},
+ };
+
+ for (auto& block : GetDocument().GetBlocks()) {
+ if (block->GetType() != Block::TYPE_STRUCTURE)
+ continue;
+
+ auto& st = static_cast<const Structure&>(*block);
+ AddTypeName(st);
+ }
+}
+
+void RsGeneratorBase::AddTypeName(const Structure& st) {
+ std::string name = st.GetID();
+ std::string type_name;
+ if (st.GetBase() != nullptr)
+ type_name = GetBaseTypeName(st.GetBase()) + "::" + name;
+ else
+ type_name = name;
+
+ struct_types_[std::move(name)] = std::move(type_name);
+}
+
+void RsGeneratorBase::OnInitGen(std::ofstream& stream) {
+ MakeDir(FileName);
+ stream.open(FileName + "/impl_internal.rs");
+ ReplaceAll(CB_COMMON_MAIN)
+ .Repeat("WRITE_PARCELS", GetDocument().GetBlocks(),
+ [&](ReplaceAll& ra, const std::shared_ptr<Block>& i) {
+ return SetParcels(ra, i);
+ })
+ .Repeat("READ_PARCELS", GetDocument().GetBlocks(),
+ [&](ReplaceAll& ra, const std::shared_ptr<Block>& i) {
+ return SetParcels(ra, i);
+ })
+ .Remove("READ_EXCEPTION", GetChannelType() == ChannelType::TYPE_GROUP)
+ .Remove("WRITE_EXCEPTION", GetChannelType() == ChannelType::TYPE_GROUP)
+ .Remove("BUNDLE_HEADER_BLOCK", HasBundle() != true)
+ .Remove("BUNDLE_BLOCK", HasBundle() != true)
+ .Repeat("WRITE_ENUMS", GetDocument().GetBlocks(),
+ [&](ReplaceAll& ra, const std::shared_ptr<Block>& i) {
+ return SetEnumParcels(ra, i);
+ })
+ .Repeat("READ_ENUMS", GetDocument().GetBlocks(),
+ [&](ReplaceAll& ra, const std::shared_ptr<Block>& i) {
+ return SetEnumParcels(ra, i);
+ })
+ .ReplaceBlock("META_PARCELS", [&](ReplaceAll& ra) {
+ return SetMetaParcelBlock(ra);
+ })
+ .Out(stream);
+ stream.close();
+}
+
+void RsGeneratorBase::OnFiniGen(std::ofstream& stream) {
+}
+
+bool RsGeneratorBase::HasBundle() {
+ for (auto& i : GetDocument().GetBlocks()) {
+ if (i->GetType() == Block::TYPE_STRUCTURE) {
+ Structure& st = static_cast<Structure&>(*i);
+ auto elms = GetElements(st);
+ for (auto& e : elms) {
+ if (ConvertTypeToString(e->GetType(), i).find("Bundle") != std::string::npos) {
+ return true;
+ }
+ }
+ } else if (i->GetType() == Block::TYPE_INTERFACE) {
+ Interface& iface = static_cast<Interface&>(*i);
+ for (auto& d : iface.GetDeclarations()) {
+ if (GetParameters(d->GetParameters()).find("Bundle") != std::string::npos) {
+ return true;
+ }
+ if (ConvertTypeToString((*d).GetType()).find("Bundle") != std::string::npos) {
+ return true;
+ }
+ }
+ }
+ }
+
+ return false;
+}
+
+bool RsGeneratorBase::SetEnum(ReplaceAll& ra, const std::unique_ptr<Enum>& e) {
+ ra.Repeat("PROPERTIES", e->GetFields(),
+ [&](ReplaceAll& ra, const std::unique_ptr<Field>& f) {
+ if (f->GetValue().empty()) {
+ ra.Replace("ID", f->GetID());
+ } else {
+ ra.Replace("ID", f->GetID() + " = " + f->GetValue());
+ }
+ return true;
+ })
+ .Replace("ENUM_NAME", e->GetID());
+ return true;
+}
+
+bool RsGeneratorBase::SetStructs(ReplaceAll& ra,
+ const std::shared_ptr<Block>& i) {
+ if (i->GetType() != Block::TYPE_STRUCTURE)
+ return false;
+
+ ra.Repeat("ENUM", i->GetEnums(),
+ [&](ReplaceAll& ra, const std::unique_ptr<Enum>& e) {
+ return SetEnum(ra, e);
+ });
+
+ Structure& st = static_cast<Structure&>(*i);
+ auto elms = GetElements(st);
+ ra.Replace("STRUCT_MOD_NAME", PascalToSnake(st.GetID()))
+ .Replace("STRUCT_NAME", st.GetID())
+ .Repeat("PROPERTIES", elms,
+ [&](ReplaceAll& ra, const std::shared_ptr<Element>& e) {
+ ra.Replace("ID", PascalToSnake(e->GetID()))
+ .Replace("TYPE", ConvertTypeToString(e->GetType(), i));
+ return true;
+ });
+ return true;
+}
+
+std::string RsGeneratorBase::GetStructTypeString(const Structure& st) {
+ std::string str;
+
+ if (st.GetBase() != nullptr) {
+ str += GetStructTypeString(*st.GetBase()) + "::";
+ }
+ str += st.GetID();
+
+ return str;
+}
+
+bool RsGeneratorBase::SetEnumParcels(ReplaceAll& ra,
+ const std::shared_ptr<Block>& i) {
+ ra.Repeat("ENUMS", i->GetEnums(), [&](ReplaceAll& ra,
+ const std::unique_ptr<Enum>& e) {
+ ra.Repeat("MATCH_PROPERTIES", e->GetFields(),
+ [&](ReplaceAll& ra, const std::unique_ptr<Field>& f) {
+ ra.Replace("FIELD", f->GetID());
+ return true;
+ })
+ .Replace("ENUM_NAME", e->GetID());
+ return true;
+ })
+ .Replace("BLOCK_NAME", PascalToSnake(i->GetID()));
+
+ return true;
+}
+
+bool RsGeneratorBase::SetParcels(ReplaceAll& ra,
+ const std::shared_ptr<Block>& i) {
+ if (i->GetType() != Block::TYPE_STRUCTURE)
+ return false;
+ const Structure& st = static_cast<const Structure&>(*i);
+ auto elms = GetElements(st);
+ ra.Replace("MOD_NAME", PascalToSnake(st.GetID()))
+ .Replace("TYPE", st.GetID())
+ .Repeat("PARCEL_BODY", elms, [&](ReplaceAll& ra,
+ const std::shared_ptr<Element>& e) {
+ ra.Replace("ID", PascalToSnake(e->GetID()));
+ return true;
+ })
+ .Repeat("UNIT_BODY", elms, [&](ReplaceAll& ra,
+ const std::shared_ptr<Element>& e) {
+ ra.Replace("ID", PascalToSnake(e->GetID()))
+ .Replace("REAL_ID", e->GetID())
+ .Replace("INSIDE_TYPE", ConvertTypeToString(e->GetType(), i, false));
+ return true;
+ })
+ .Replace("UNIT_TYPE", GetStructTypeString(st));
+ return true;
+}
+
+void RsGeneratorBase::SetMetaParcelBlock(ReplaceAll& ra) {
+ meta_type_list_.clear();
+ for (auto& i : GetDocument().GetBlocks()) {
+ if (i->GetType() == Block::TYPE_STRUCTURE) {
+ const Structure& st = static_cast<const Structure&>(*i);
+ for (const auto& j : st.GetElements()) {
+ auto& t = j->GetType();
+ AddMetaTypeList(t);
+ }
+ } else if (i->GetType() == Block::TYPE_INTERFACE) {
+ const Interface& iface = static_cast<const Interface&>(*i);
+ for (const auto& j : iface.GetDeclarations()) {
+ auto& t = j->GetType();
+ AddMetaTypeList(t);
+ for (const auto& k : j->GetParameters()) {
+ auto& t1 = k->GetParameterType().GetBaseType();
+ AddMetaTypeList(t1);
+ }
+ }
+ }
+ }
+
+ std::string ret;
+ for (auto& p : meta_type_list_) {
+ const BaseType& type = *(p.second);
+ ReplaceAll target = ra;
+ std::string unit_str, value_str;
+ std::string inside_str, inside_value_str;
+
+ if (type.GetMetaType()) {
+ unit_str = type.GetMetaType()->ToString();
+ inside_str = ConvertTypeToString(*type.GetMetaType());
+ } else {
+ if (type.GetKeyType()) {
+ unit_str = type.GetKeyType()->ToString();
+ inside_str = ConvertTypeToString(*type.GetKeyType());
+ }
+
+ if (type.GetValueType()) {
+ value_str = type.GetValueType()->ToString();
+ inside_value_str = ConvertTypeToString(
+ *type.GetValueType(), nullptr, false);
+ }
+ }
+
+ target.Replace("TYPE", ConvertTypeToString(type, nullptr, false))
+ .Replace("TYPE_ID", GetFullNameFromType(type))
+ .RemoveAll("LIST", type.ToString() != "list")
+ .RemoveAll("ARRAY", type.ToString() != "array")
+ .RemoveAll("SET", type.ToString() != "set")
+ .RemoveAll("MAP", type.ToString() != "map")
+ .Replace("UNIT_TYPE", unit_str)
+ .Replace("UNIT_VALUE_TYPE", value_str)
+ .Replace("INSIDE_TYPE", inside_str)
+ .Replace("INSIDE_VALUE_TYPE", inside_value_str);
+ ret += target;
+ }
+
+ ra = ReplaceAll(ret);
+}
+
+void RsGeneratorBase::AddMetaTypeList(const BaseType& type) {
+ if (type.GetMetaType() != nullptr) {
+ meta_type_list_[ConvertTypeToString(type)] = &type;
+ AddMetaTypeList(*type.GetMetaType());
+ }
+
+ if (type.GetValueType() != nullptr) {
+ auto value_type = type.GetValueType();
+ meta_type_list_[ConvertTypeToString(type)] = &type;
+ if (value_type->GetMetaType() != nullptr)
+ AddMetaTypeList(*value_type);
+ }
+
+}
+
+std::string RsGeneratorBase::GetFullNameFromType(const BaseType& type) {
+ auto found = struct_types_.find(type.GetFullName(true));
+ if (found != struct_types_.end())
+ return found->second;
+
+ if (type.IsEnumType())
+ return "int";
+
+ if (IsDelegateType(type) ||
+ type.ToString().find("::CallbackBase") != std::string::npos)
+ return "delegate";
+
+ std::string name = type.GetFullName(true);
+ return GetEnumTypeString(name, true);
+}
+
+std::string RsGeneratorBase::GetEnumTypeString(const std::string& type,
+ bool use_underbar) {
+ std::string concatenated_char = use_underbar ? "_" : "::";
+ auto pos = type.find('.');
+ if (pos == std::string::npos) {
+ std::string cls_name = GetClassNameFromEnumType(type);
+ if (!cls_name.empty())
+ return PascalToSnake(cls_name) + concatenated_char + type;
+
+ return type;
+ }
+
+ std::string block_id = type.substr(0, pos);
+ std::string type_id = type.substr(pos + 1, type.size() - (pos + 1));
+ return block_id + concatenated_char + type_id;
+}
+
+std::string RsGeneratorBase::GetClassNameFromEnumType(const std::string& type) {
+ for (auto& block : GetDocument().GetBlocks()) {
+ for (const auto& e : block->GetEnums()) {
+ if (e->GetID() == type)
+ return block->GetID();
+ }
+ }
+
+ return {};
+}
+
+std::string RsGeneratorBase::ConvertTypeToString(const BaseType& type,
+ const std::shared_ptr<Block>& i, bool definition) {
+ if (type.IsEnumType()) {
+ std::string str = type.ToString();
+ size_t pos = str.find(".");
+ if (pos != std::string::npos) {
+ while (pos != std::string::npos) {
+ str.replace(pos, 1, "::");
+ str = PascalToSnake(str.substr(0, pos)) + str.substr(pos);
+ pos = str.find(".");
+ }
+ return str;
+ } else {
+ if (i != nullptr && i->GetType() == Block::TYPE_STRUCTURE) {
+ const Structure& st = static_cast<const Structure&>(*i);
+ std::string base_id = st.GetEnumBaseID(str);
+ if (!base_id.empty())
+ return base_id + "::" + str;
+ else if (!definition)
+ return PascalToSnake(st.GetID()) + "::" +str;
+ else
+ return str;
+ } else {
+ if (!definition) {
+ for (auto& block : GetDocument().GetBlocks()) {
+ if (block->GetType() == Block::TYPE_STRUCTURE)
+ continue;
+ for (const auto& e : block->GetEnums()) {
+ if (e->GetID() == type.ToString())
+ return PascalToSnake(block->GetID()) + "::" + type.ToString();
+ }
+ }
+ }
+ }
+ }
+ }
+
+ if (type.IsStructureType())
+ return PascalToSnake(type.ToString()) + "::" + type.ToString();
+
+ if (type.IsUserDefinedType())
+ return type.ToString();
+
+ if (type.GetMetaType() != nullptr)
+ return type_map_[type.ToString()] + "<" +
+ ConvertTypeToString(*(type.GetMetaType()), i, definition) + ">";
+
+ if (type.GetKeyType() != nullptr && type.GetValueType() != nullptr) {
+ return type_map_[type.ToString()] + "<" +
+ ConvertTypeToString(*(type.GetKeyType()), i, definition) + ", " +
+ ConvertTypeToString(*(type.GetValueType()), i, definition) + ">";
+ }
+ return type_map_[type.ToString()];
+}
+
+std::string RsGeneratorBase::GetParameters(const Parameters& ps, bool with_id) {
+ std::string ret;
+ for (const auto& i : ps) {
+ if (!ret.empty()) {
+ ret += ", ";
+ }
+
+ std::string mut;
+ auto dir = i->GetParameterType().GetDirection();
+ if (dir == ParameterType::Direction::OUT ||
+ dir == ParameterType::Direction::REF) {
+ mut = "&mut ";
+ }
+
+ std::string life_time;
+ if (IsDelegateType(i->GetParameterType().GetBaseType())) {
+ if (IsProxy())
+ life_time = "<'b>";
+ }
+ if (with_id)
+ ret += i->GetID() + ": " + mut +
+ ConvertTypeToString(i->GetParameterType().GetBaseType()) +
+ life_time;
+ else
+ ret += mut + ConvertTypeToString(i->GetParameterType().GetBaseType()) +
+ life_time;
+ }
+
+ return ret;
+}
+
+std::string RsGeneratorBase::GetParameterIDs(const Parameters& ps) {
+ std::string ret;
+ for (const auto& i : ps) {
+ if (!ret.empty()) {
+ ret += ", ";
+ }
+
+ ret += i->GetID();
+ }
+
+ return ret;
+}
+
+std::string RsGeneratorBase::GetParameterIDsWithDir(const Parameters& ps) {
+ std::string ret;
+ for (const auto& i : ps) {
+ if (!ret.empty()) {
+ ret += ", ";
+ }
+
+ if (i->GetParameterType().GetDirection() == ParameterType::Direction::OUT
+ || i->GetParameterType().GetDirection() == ParameterType::Direction::REF)
+ ret += "&mut ";
+ ret += i->GetID();
+ }
+
+ return ret;
+}
+
+void RsGeneratorBase::MakeDir(const std::string& path) {
+ if (access(path.c_str(), F_OK) == 0)
+ return;
+
+ mode_t mod = (S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH | 02000);
+ mkdir(path.c_str(), mod);
+}
+
+} // namespace version2
+} // namespace tidl
+
--- /dev/null
+/*
+ * Copyright (c) 2024 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef IDLC_GEN_VERSION2_RS_GEN_BASE_H_
+#define IDLC_GEN_VERSION2_RS_GEN_BASE_H_
+
+#include <memory>
+#include <string>
+#include <unordered_map>
+
+#include "idlc/ast/type.h"
+#include "idlc/ast/structure.h"
+#include "idlc/gen/generator.h"
+
+namespace tidl {
+namespace version2 {
+
+class RsGeneratorBase : public Generator {
+ public:
+ explicit RsGeneratorBase(std::shared_ptr<Document> doc);
+ virtual ~RsGeneratorBase() = default;
+
+ void AddTypeName(const Structure& st);
+ void OnInitGen(std::ofstream& stream) override;
+ void OnFiniGen(std::ofstream& stream) override;
+
+ std::string ConvertTypeToString(const BaseType& type,
+ const std::shared_ptr<Block>& i = nullptr, bool definition = true);
+ std::string GetParameters(const Parameters& ps, bool with_id = true);
+ std::string GetParameterIDs(const Parameters& ps);
+ std::string GetParameterIDsWithDir(const Parameters& ps);
+ void MakeDir(const std::string& path);
+ std::string GetFullNameFromType(const BaseType& type);
+ bool SetEnum(ReplaceAll& ra, const std::unique_ptr<Enum>& e);
+ bool SetStructs(ReplaceAll& ra, const std::shared_ptr<Block>& i);
+ bool HasBundle();
+ protected:
+ const int TAB_SIZE = 4;
+
+ private:
+ bool SetParcels(ReplaceAll& ra, const std::shared_ptr<Block>& i);
+ bool SetEnumParcels(ReplaceAll& ra, const std::shared_ptr<Block>& i);
+ void SetMetaParcelBlock(ReplaceAll& ra);
+ void AddMetaTypeList(const BaseType& type);
+
+ std::string GetEnumTypeString(const std::string& type, bool use_underbar);
+ std::string GetClassNameFromEnumType(const std::string& type);
+ std::string GetStructTypeString(const Structure& st);
+
+ std::unordered_map<std::string, std::string> type_map_;
+ std::unordered_map<std::string, const BaseType*> meta_type_list_;
+ std::unordered_map<std::string, std::string> struct_types_;
+ std::unordered_map<std::string, std::string> parcel_type_map_;
+ std::unordered_map<std::string, std::string> type_init_map_;
+ std::unordered_map<std::string, BaseType> unit_types_;
+};
+
+} // namespace version2
+} // namespace tidl
+
+#endif // IDLC_GEN_VERSION2_RS_GEN_BASE_H_
--- /dev/null
+/*
+ * Copyright (c) 2024 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef IDLC_GEN_VERSION2_RS_GEN_BASE_CB_H_
+#define IDLC_GEN_VERSION2_RS_GEN_BASE_CB_H_
+
+constexpr const char CB_COMMON_MAIN[] =
+R"__rs_cb(
+extern crate rust_rpc_port;
+<BUNDLE_HEADER_BLOCK?>
+extern crate tizen_bundle;
+
+use tizen_bundle::tizen_bundle::Bundle;
+</BUNDLE_HEADER_BLOCK?>
+use rust_rpc_port::parcel::Parcel;
+use std::collections::{LinkedList, HashMap, HashSet};
+use super::*;
+
+macro_rules! DLOG_DEBUG { () => {3}; }
+macro_rules! DLOG_INFO { () => {4}; }
+macro_rules! DLOG_WARN { () => {5}; }
+macro_rules! DLOG_ERROR { () => {6}; }
+
+macro_rules! DLOG {
+ ($prio:expr, $($arg:tt)*) => {{
+ use std::ffi::c_int;
+
+ #[link(name = "dlog")]
+ extern "C" {
+ pub fn __dlog_print(
+ log_id: c_int,
+ ...
+ ) -> c_int;
+ }
+
+ fn f() {}
+ fn type_name_of<T>(_: T) -> &'static str {
+ std::any::type_name::<T>()
+ }
+ let prio = $prio;
+ let full_func_name = type_name_of(f).strip_suffix("::f").unwrap();
+ let func_name = &full_func_name[full_func_name.rfind("::").unwrap()+2..];
+ let file_path = std::path::PathBuf::from(file!());
+ let file_name = file_path.file_name().unwrap().to_str().unwrap();
+ let total_log = format!("{}: {}({}): {}\0", file_name, func_name, line!(), format_args!($($arg)*).to_string());
+ unsafe { __dlog_print(0, prio, "RUST_RPC_PORT\0".as_ptr(), total_log.as_ptr()); }
+ }}
+}
+
+macro_rules! debug { ($($arg:tt)*) => {{ DLOG!(DLOG_DEBUG!(), $($arg)*); }} }
+
+macro_rules! info { ($($arg:tt)*) => {{ DLOG!(DLOG_INFO!(), $($arg)*); }} }
+
+macro_rules! warn { ($($arg:tt)*) => {{ DLOG!(DLOG_WARN!(), $($arg)*); }} }
+
+macro_rules! error { ($($arg:tt)*) => {{ DLOG!(DLOG_ERROR!(), $($arg)*); }} }
+
+#[derive(Debug)]
+pub struct Unit {
+ parcel: Parcel,
+ name: String,
+ ty: String,
+}
+
+#[derive(Debug)]
+pub struct UnitMap {
+ map: HashMap<String, Unit>,
+}
+
+pub trait Writeable {
+ fn write_parcel(&self, parcel: &mut Parcel);
+ fn write_unit(&self, unit: &mut Unit);
+ fn write_unitmap(&self, name: &str, unit_map: &mut UnitMap);
+}
+
+pub trait Readable {
+ fn read_parcel(&mut self, parcel: &Parcel);
+ fn read_unit(&mut self, unit: &Unit);
+ fn read_unitmap(&mut self, name: String, unit_map: &UnitMap);
+}
+
+impl Unit {
+ pub fn empty() -> Self {
+ Unit {
+ parcel: Parcel::new_without_header(),
+ name: String::new(),
+ ty: String::new(),
+ }
+ }
+ pub fn new(name: String, ty: String) -> Self {
+ Unit {
+ parcel: Parcel::new_without_header(),
+ name,
+ ty,
+ }
+ }
+
+ pub fn set_name(&mut self, name: String) {
+ self.name = name;
+ }
+
+ pub fn set_type(&mut self, ty: String) {
+ self.ty = ty;
+ }
+
+ pub fn get_name(&self) -> &String {
+ &self.name
+ }
+
+ pub fn get_type(&self) -> &String {
+ &self.ty
+ }
+
+ pub fn get_parcel(&self) -> &Parcel {
+ &self.parcel
+ }
+
+ pub fn get_mut_parcel(&mut self) -> &mut Parcel {
+ &mut self.parcel
+ }
+
+ pub fn serialize(&self, parcel: &mut Parcel) {
+ parcel.write_str(self.name.as_str());
+ parcel.write_str(self.ty.as_str());
+
+ let raw = self.parcel.get_raw();
+ parcel.write_array_count(raw.len());
+ parcel.write(raw);
+ }
+
+ pub fn deserialize(&mut self, parcel: &Parcel) {
+ self.set_name(parcel.read_string());
+ self.set_type(parcel.read_string());
+ let size = parcel.read_array_count();
+ let mut raw = Vec::<u8>::with_capacity(size);
+ raw.resize(size, 0);
+ let mut raw_slice: &mut [u8] = raw.as_mut_slice();
+ parcel.read(raw_slice);
+ self.parcel.write(raw_slice);
+ }
+
+ pub fn read(&self, data: &mut dyn Readable) {
+ data.read_unit(self);
+ }
+
+ pub fn write(&mut self, data: &dyn Writeable) {
+ data.write_unit(self);
+ }
+}
+
+impl UnitMap {
+ pub fn new() -> Self {
+ Self {
+ map: HashMap::new(),
+ }
+ }
+
+ pub fn clear(&mut self) {
+ self.map.clear();
+ }
+
+ pub fn len(&self) -> usize {
+ self.map.len()
+ }
+
+ pub fn insert(&mut self, name: String, unit: Unit) {
+ self.map.insert(name, unit);
+ }
+
+ pub fn lookup(&self, name: &str) -> Option<&Unit> {
+ self.map.get(name)
+ }
+
+ pub fn serialize(&self, parcel: &mut Parcel) {
+ parcel.write_array_count(self.len() as usize);
+ for unit in self.map.values() {
+ unit.serialize(parcel);
+ }
+ }
+
+ pub fn deserialize(&mut self, parcel: &Parcel) {
+ let size = parcel.read_array_count();
+ for _ in 0..size {
+ let mut unit = Unit::empty();
+ unit.deserialize(parcel);
+ let name = unit.get_name();
+ self.insert(String::from(name), unit);
+ }
+ }
+
+ pub fn read(&self, name: &str, data: &mut dyn Readable) {
+ let unit = self.lookup(name);
+ if let Some(unit) = unit {
+ unit.read(data);
+ } else {
+ panic!("Unit {} not found", name);
+ }
+ }
+}
+
+impl Writeable for i8 {
+ fn write_parcel(&self, parcel: &mut Parcel) {
+ parcel.write_i8(*self);
+ }
+ fn write_unit(&self, unit: &mut Unit) {
+ self.write_parcel(unit.get_mut_parcel());
+ }
+ fn write_unitmap(&self, name: &str, unit_map: &mut UnitMap) {
+ let mut unit = Unit::new(String::from(name), String::from("char"));
+ unit.write(self);
+ unit_map.insert(String::from(name), unit);
+ }
+}
+
+impl Writeable for i16 {
+ fn write_parcel(&self, parcel: &mut Parcel) {
+ parcel.write_i16(*self);
+ }
+ fn write_unit(&self, unit: &mut Unit) {
+ self.write_parcel(unit.get_mut_parcel());
+ }
+ fn write_unitmap(&self, name: &str, unit_map: &mut UnitMap) {
+ let mut unit = Unit::new(String::from(name), String::from("short"));
+ unit.write(self);
+ unit_map.insert(String::from(name), unit);
+ }
+}
+
+impl Writeable for i32 {
+ fn write_parcel(&self, parcel: &mut Parcel) {
+ parcel.write_i32(*self);
+ }
+ fn write_unit(&self, unit: &mut Unit) {
+ self.write_parcel(unit.get_mut_parcel());
+ }
+ fn write_unitmap(&self, name: &str, unit_map: &mut UnitMap) {
+ let mut unit = Unit::new(String::from(name), String::from("int"));
+ unit.write(self);
+ unit_map.insert(String::from(name), unit);
+ }
+}
+
+impl Writeable for i64 {
+ fn write_parcel(&self, parcel: &mut Parcel) {
+ parcel.write_i64(*self);
+ }
+ fn write_unit(&self, unit: &mut Unit) {
+ self.write_parcel(unit.get_mut_parcel());
+ }
+ fn write_unitmap(&self, name: &str, unit_map: &mut UnitMap) {
+ let mut unit = Unit::new(String::from(name), String::from("long"));
+ unit.write(self);
+ unit_map.insert(String::from(name), unit);
+ }
+}
+
+impl Writeable for f32 {
+ fn write_parcel(&self, parcel: &mut Parcel) {
+ parcel.write_f32(*self);
+ }
+ fn write_unit(&self, unit: &mut Unit) {
+ self.write_parcel(unit.get_mut_parcel());
+ }
+ fn write_unitmap(&self, name: &str, unit_map: &mut UnitMap) {
+ let mut unit = Unit::new(String::from(name), String::from("float"));
+ unit.write(self);
+ unit_map.insert(String::from(name), unit);
+ }
+}
+
+impl Writeable for f64 {
+ fn write_parcel(&self, parcel: &mut Parcel) {
+ parcel.write_f64(*self);
+ }
+ fn write_unit(&self, unit: &mut Unit) {
+ self.write_parcel(unit.get_mut_parcel());
+ }
+ fn write_unitmap(&self, name: &str, unit_map: &mut UnitMap) {
+ let mut unit = Unit::new(String::from(name), String::from("double"));
+ unit.write(self);
+ unit_map.insert(String::from(name), unit);
+ }
+}
+
+impl Writeable for bool {
+ fn write_parcel(&self, parcel: &mut Parcel) {
+ parcel.write_bool(*self);
+ }
+ fn write_unit(&self, unit: &mut Unit) {
+ self.write_parcel(unit.get_mut_parcel());
+ }
+ fn write_unitmap(&self, name: &str, unit_map: &mut UnitMap) {
+ let mut unit = Unit::new(String::from(name), String::from("bool"));
+ unit.write(self);
+ unit_map.insert(String::from(name), unit);
+ }
+}
+
+impl Writeable for String {
+ fn write_parcel(&self, parcel: &mut Parcel) {
+ parcel.write_str(&*self);
+ }
+ fn write_unit(&self, unit: &mut Unit) {
+ self.write_parcel(unit.get_mut_parcel());
+ }
+ fn write_unitmap(&self, name: &str, unit_map: &mut UnitMap) {
+ let mut unit = Unit::new(String::from(name), String::from("string"));
+ unit.write(self);
+ unit_map.insert(String::from(name), unit);
+ }
+}
+
+<WRITE_ENUMS*>
+<ENUMS*>
+impl Writeable for <BLOCK_NAME>::<ENUM_NAME> {
+ fn write_parcel(&self, parcel: &mut Parcel) {
+ parcel.write_i32((*self) as i32);
+ }
+ fn write_unit(&self, unit: &mut Unit) {
+ self.write_parcel(unit.get_mut_parcel());
+ }
+ fn write_unitmap(&self, name: &str, unit_map: &mut UnitMap) {
+ let mut unit = Unit::new(String::from(name), String::from("int"));
+ unit.write(self);
+ unit_map.insert(String::from(name), unit);
+ }
+}
+
+</ENUMS*>
+</WRITE_ENUMS*>
+<WRITE_EXCEPTION?>
+impl Writeable for RemoteException {
+ fn write_parcel(&self, parcel: &mut Parcel) {
+ parcel.write_i32(self.cause);
+ parcel.write_str(self.message.as_str());
+ }
+
+ fn write_unit(&self, unit: &mut Unit) {
+ let mut unit_map = UnitMap::new();
+ self.cause.write_unitmap("cause", &mut unit_map);
+ self.message.write_unitmap("message", &mut unit_map);
+ unit_map.serialize(unit.get_mut_parcel());
+ }
+
+ fn write_unitmap(&self, name: &str, unit_map: &mut UnitMap) {
+ let mut unit = Unit::new(String::from(name), "remote_exception".to_owned());
+ unit.write(self);
+ unit_map.insert(String::from(name), unit);
+ }
+}
+
+</WRITE_EXCEPTION?>
+
+impl Readable for i8 {
+ fn read_parcel(&mut self, parcel: &Parcel) {
+ *self = parcel.read_i8();
+ }
+ fn read_unit(&mut self, unit: &Unit) {
+ self.read_parcel(unit.get_parcel());
+ }
+ fn read_unitmap(&mut self, name: String, unit_map: &UnitMap) {
+ match unit_map.lookup(name.as_str()) {
+ Some(unit) => {
+ if unit.get_type().ne(&"char") {
+ error!("type({}) is not char", unit.get_type());
+ return;
+ }
+
+ unit.read(self);
+ }
+ None => {
+ error!("Failed to find {}", name);
+ return;
+ }
+ }
+ }
+}
+
+impl Readable for i16 {
+ fn read_parcel(&mut self, parcel: &Parcel) {
+ *self = parcel.read_i16();
+ }
+ fn read_unit(&mut self, unit: &Unit) {
+ self.read_parcel(unit.get_parcel());
+ }
+ fn read_unitmap(&mut self, name: String, unit_map: &UnitMap) {
+ match unit_map.lookup(name.as_str()) {
+ Some(unit) => {
+ if unit.get_type().ne(&"short") {
+ error!("type({}) is not short", unit.get_type());
+ return;
+ }
+
+ unit.read(self);
+ }
+ None => {
+ error!("Failed to find {}", name);
+ return;
+ }
+ }
+ }
+}
+
+impl Readable for i32 {
+ fn read_parcel(&mut self, parcel: &Parcel) {
+ *self = parcel.read_i32();
+ }
+ fn read_unit(&mut self, unit: &Unit) {
+ self.read_parcel(unit.get_parcel());
+ }
+ fn read_unitmap(&mut self, name: String, unit_map: &UnitMap) {
+ match unit_map.lookup(name.as_str()) {
+ Some(unit) => {
+ if unit.get_type().ne(&"int") {
+ error!("type({}) is not int", unit.get_type());
+ return;
+ }
+
+ unit.read(self);
+ }
+ None => {
+ error!("Failed to find {}", name);
+ return;
+ }
+ }
+ }
+}
+
+impl Readable for i64 {
+ fn read_parcel(&mut self, parcel: &Parcel) {
+ *self = parcel.read_i64();
+ }
+ fn read_unit(&mut self, unit: &Unit) {
+ self.read_parcel(unit.get_parcel());
+ }
+ fn read_unitmap(&mut self, name: String, unit_map: &UnitMap) {
+ match unit_map.lookup(name.as_str()) {
+ Some(unit) => {
+ if unit.get_type().ne(&"long") {
+ error!("type({}) is not long", unit.get_type());
+ return;
+ }
+
+ unit.read(self);
+ }
+ None => {
+ error!("Failed to find {}", name);
+ return;
+ }
+ }
+ }
+}
+
+impl Readable for f32 {
+ fn read_parcel(&mut self, parcel: &Parcel) {
+ *self = parcel.read_f32();
+ }
+ fn read_unit(&mut self, unit: &Unit) {
+ self.read_parcel(unit.get_parcel());
+ }
+ fn read_unitmap(&mut self, name: String, unit_map: &UnitMap) {
+ match unit_map.lookup(name.as_str()) {
+ Some(unit) => {
+ if unit.get_type().ne(&"float") {
+ error!("type({}) is not float", unit.get_type());
+ return;
+ }
+
+ unit.read(self);
+ }
+ None => {
+ error!("Failed to find {}", name);
+ return;
+ }
+ }
+ }
+}
+
+impl Readable for f64 {
+ fn read_parcel(&mut self, parcel: &Parcel) {
+ *self = parcel.read_f64();
+ }
+ fn read_unit(&mut self, unit: &Unit) {
+ self.read_parcel(unit.get_parcel());
+ }
+ fn read_unitmap(&mut self, name: String, unit_map: &UnitMap) {
+ match unit_map.lookup(name.as_str()) {
+ Some(unit) => {
+ if unit.get_type().ne(&"double") {
+ error!("type({}) is not double", unit.get_type());
+ return;
+ }
+
+ unit.read(self);
+ }
+ None => {
+ error!("Failed to find {}", name);
+ return;
+ }
+ }
+ }
+}
+
+impl Readable for bool {
+ fn read_parcel(&mut self, parcel: &Parcel) {
+ *self = parcel.read_bool();
+ }
+ fn read_unit(&mut self, unit: &Unit) {
+ self.read_parcel(unit.get_parcel());
+ }
+ fn read_unitmap(&mut self, name: String, unit_map: &UnitMap) {
+ match unit_map.lookup(name.as_str()) {
+ Some(unit) => {
+ if unit.get_type().ne(&"bool") {
+ error!("type({}) is not bool", unit.get_type());
+ return;
+ }
+
+ unit.read(self);
+ }
+ None => {
+ error!("Failed to find {}", name);
+ return;
+ }
+ }
+ }
+}
+
+impl Readable for String {
+ fn read_parcel(&mut self, parcel: &Parcel) {
+ *self = parcel.read_string();
+ }
+ fn read_unit(&mut self, unit: &Unit) {
+ self.read_parcel(unit.get_parcel());
+ }
+ fn read_unitmap(&mut self, name: String, unit_map: &UnitMap) {
+ match unit_map.lookup(name.as_str()) {
+ Some(unit) => {
+ if unit.get_type().ne(&"string") {
+ error!("type({}) is not string", unit.get_type());
+ return;
+ }
+
+ unit.read(self);
+ }
+ None => {
+ error!("Failed to find {}", name);
+ return;
+ }
+ }
+ }
+}
+
+<BUNDLE_BLOCK?>
+impl Writeable for Bundle {
+ fn write_parcel(&self, parcel: &mut Parcel) {
+ parcel.write_bundle(&*self);
+ }
+ fn write_unit(&self, unit: &mut Unit) {
+ self.write_parcel(unit.get_mut_parcel());
+ }
+ fn write_unitmap(&self, name: &str, unit_map: &mut UnitMap) {
+ let mut unit = Unit::new(String::from(name), String::from("bundle"));
+ unit.write(self);
+ unit_map.insert(String::from(name), unit);
+ }
+}
+
+impl Readable for Bundle {
+ fn read_parcel(&mut self, parcel: &Parcel) {
+ *self = parcel.read_bundle() as Bundle;
+ }
+ fn read_unit(&mut self, unit: &Unit) {
+ self.read_parcel(unit.get_parcel());
+ }
+ fn read_unitmap(&mut self, name: String, unit_map: &UnitMap) {
+ match unit_map.lookup(name.as_str()) {
+ Some(unit) => {
+ if unit.get_type().ne(&"bundle") {
+ error!("type({}) is not bundle", unit.get_type());
+ return;
+ }
+
+ unit.read(self);
+ }
+ None => {
+ error!("Failed to find {}", name);
+ return;
+ }
+ }
+ }
+}
+</BUNDLE_BLOCK?>
+
+<READ_ENUMS*>
+<ENUMS*>
+impl From<i32> for <BLOCK_NAME>::<ENUM_NAME> {
+ fn from(value: i32) -> Self {
+ match value {
+ <MATCH_PROPERTIES*>
+ x if x == <BLOCK_NAME>::<ENUM_NAME>::<FIELD> as i32 => <BLOCK_NAME>::<ENUM_NAME>::<FIELD>,
+ </MATCH_PROPERTIES*>
+ _ => <BLOCK_NAME>::<ENUM_NAME>::DEFAULT
+ }
+ }
+}
+
+impl Readable for <BLOCK_NAME>::<ENUM_NAME> {
+ fn read_parcel(&mut self, parcel: &Parcel) {
+ *self = parcel.read_i32().into();
+ }
+ fn read_unit(&mut self, unit: &Unit) {
+ self.read_parcel(unit.get_parcel());
+ }
+ fn read_unitmap(&mut self, name: String, unit_map: &UnitMap) {
+ match unit_map.lookup(name.as_str()) {
+ Some(unit) => {
+ if unit.get_type().ne(&"int") {
+ error!("type({}) is not int", unit.get_type());
+ return;
+ }
+
+ unit.read(self);
+ }
+ None => {
+ error!("Failed to find {}", name);
+ return;
+ }
+ }
+ }
+}
+
+</ENUMS*>
+</READ_ENUMS*>
+<READ_EXCEPTION?>
+impl Readable for RemoteException {
+ fn read_parcel(&mut self, parcel: &Parcel) {
+ self.cause = parcel.read_i32();
+ self.message = parcel.read_string();
+ }
+ fn read_unit(&mut self, unit: &Unit) {
+ let mut unit_map = UnitMap::new();
+ unit_map.deserialize(unit.get_parcel());
+ unit_map.read("cause", &mut self.cause);
+ unit_map.read("message", &mut self.message);
+ }
+ fn read_unitmap(&mut self, name: String, unit_map: &UnitMap) {
+ match unit_map.lookup(name.as_str()) {
+ Some(unit) => {
+ if unit.get_type().ne(&"remote_exception") {
+ error!("type({}) is not remote_exception", unit.get_type());
+ return;
+ }
+
+ unit.read(self);
+ }
+ None => {
+ error!("Failed to find {}", name);
+ return;
+ }
+ }
+ }
+}
+
+</READ_EXCEPTION?>
+<WRITE_PARCELS*>
+impl Writeable for <MOD_NAME>::<TYPE> {
+ fn write_parcel(&self, parcel: &mut Parcel) {
+ <PARCEL_BODY*>
+ self.<ID>.write_parcel(parcel);
+ </PARCEL_BODY*>
+ }
+ fn write_unit(&self, unit: &mut Unit) {
+ let mut __unit_map = UnitMap::new();
+ <UNIT_BODY*>
+ self.<ID>.write_unitmap("<REAL_ID>", &mut __unit_map);
+ </UNIT_BODY*>
+
+ __unit_map.serialize(unit.get_mut_parcel());
+ }
+ fn write_unitmap(&self, name: &str, unit_map: &mut UnitMap) {
+ let mut unit = Unit::new(String::from(name), String::from("<UNIT_TYPE>"));
+ unit.write(self);
+ unit_map.insert(String::from(name), unit);
+ }
+}
+</WRITE_PARCELS*>
+
+<READ_PARCELS*>
+impl Readable for <MOD_NAME>::<TYPE> {
+ fn read_parcel(&mut self, parcel: &Parcel) {
+ <PARCEL_BODY*>
+ self.<ID>.read_parcel(parcel);
+ </PARCEL_BODY*>
+ }
+ fn read_unit(&mut self, unit: &Unit) {
+ let mut __unit_map = UnitMap::new();
+ __unit_map.deserialize(unit.get_parcel());
+ <UNIT_BODY*>
+ let mut tmp_<ID>: <INSIDE_TYPE> = Default::default();
+ __unit_map.read("<REAL_ID>", &mut tmp_<ID>);
+ self.<ID> = tmp_<ID>;
+ </UNIT_BODY*>
+ }
+ fn read_unitmap(&mut self, name: String, unit_map: &UnitMap) {
+ match unit_map.lookup(name.as_str()) {
+ Some(unit) => {
+ if unit.get_type().ne(&"<UNIT_TYPE>") {
+ error!("type({}) is not <UNIT_TYPE>", unit.get_type());
+ return;
+ }
+
+ unit.read(self);
+ }
+ None => {
+ error!("Failed to find {}", name);
+ return;
+ }
+ }
+ }
+}
+</READ_PARCELS*>
+
+<META_PARCELS!>
+impl Writeable for <TYPE> {
+ fn write_parcel(&self, parcel: &mut Parcel) {
+ }
+ fn write_unit(&self, unit: &mut Unit) {
+ let mut __unit_map = UnitMap::new();
+ <LIST?>
+ let mut __unit = Unit::new("length".to_owned(), "int".to_owned());
+ __unit.write(&(self.len() as i32));
+ __unit_map.insert("length".to_owned(), __unit);
+ for (index, e) in self.iter().enumerate() {
+ let mut __unit = Unit::new(index.to_string(), "<UNIT_TYPE>".to_owned());
+ __unit.write(e);
+ __unit_map.insert(index.to_string(), __unit);
+ }
+ </LIST?>
+ <ARRAY?>
+ let mut __unit = Unit::new("size".to_owned(), "int".to_owned());
+ __unit.write(&(self.len() as i32));
+ __unit_map.insert("size".to_owned(), __unit);
+ for (index, e) in self.iter().enumerate() {
+ let mut __unit = Unit::new(index.to_string(), "<UNIT_TYPE>".to_owned());
+ __unit.write(e);
+ __unit_map.insert(index.to_string(), __unit);
+ }
+ </ARRAY?>
+ <SET?>
+ let mut __unit = Unit::new("size".to_owned(), "int".to_owned());
+ __unit.write(&(self.len() as i32));
+ __unit_map.insert("size".to_owned(), __unit);
+ for (index, e) in self.iter().enumerate() {
+ let key_str = format!("{}{}", String::from("key-"), index);
+ let mut __unit = Unit::new(key_str.clone(), "<UNIT_TYPE>".to_owned());
+ __unit.write(e);
+ __unit_map.insert(key_str, __unit);
+ }
+ </SET?>
+ <MAP?>
+ let mut __unit = Unit::new("size".to_owned(), "int".to_owned());
+ __unit.write(&(self.len() as i32));
+ __unit_map.insert("size".to_owned(), __unit);
+ for (index, (key, value)) in self.iter().enumerate() {
+ let key_str = format!("{}{}", String::from("key-"), index);
+ let mut __unit = Unit::new(key_str.clone(), "<UNIT_TYPE>".to_owned());
+ __unit.write(key);
+ __unit_map.insert(key_str, __unit);
+ let value_str = format!("{}{}", String::from("value-"), index);
+ let mut __unit = Unit::new(value_str.clone(), "<UNIT_VALUE_TYPE>".to_owned());
+ __unit.write(value);
+ __unit_map.insert(value_str, __unit);
+ }
+ </MAP?>
+ __unit_map.serialize(unit.get_mut_parcel());
+ }
+ fn write_unitmap(&self, name: &str, unit_map: &mut UnitMap) {
+ let mut unit = Unit::new(String::from(name), String::from("<TYPE_ID>"));
+ unit.write(self);
+ unit_map.insert(String::from(name), unit);
+ }
+}
+
+impl Readable for <TYPE> {
+ fn read_parcel(&mut self, parcel: &Parcel) {
+ }
+ fn read_unit(&mut self, unit: &Unit) {
+ let mut __unit_map = UnitMap::new();
+ __unit_map.deserialize(unit.get_parcel());
+ let mut __size: i32 = Default::default();
+ <LIST?>
+ __unit_map.read("length", &mut __size);
+ for index in 0..__size {
+ let mut __tmp_value: <INSIDE_TYPE> = Default::default();
+ __unit_map.read(&index.to_string(), &mut __tmp_value);
+ self.push_back(__tmp_value);
+ }
+ </LIST?>
+ <ARRAY?>
+ __unit_map.read("size", &mut __size);
+ for index in 0..__size {
+ let mut __tmp_value: <INSIDE_TYPE> = Default::default();
+ __unit_map.read(&index.to_string(), &mut __tmp_value);
+ self.push(__tmp_value);
+ }
+ </ARRAY?>
+ <SET?>
+ __unit_map.read("size", &mut __size);
+ for index in 0..__size {
+ let key_str = format!("{}{}", String::from("key-"), index);
+ let mut __tmp_value: <INSIDE_TYPE> = Default::default();
+ __unit_map.read(&key_str, &mut __tmp_value);
+ self.insert(__tmp_value);
+ }
+ </SET?>
+ <MAP?>
+ __unit_map.read("size", &mut __size);
+ for index in 0..__size {
+ let key_str = format!("{}{}", String::from("key-"), index);
+ let value_str = format!("{}{}", String::from("value-"), index);
+ let mut __tmp_key: <INSIDE_TYPE> = Default::default();
+ let mut __tmp_value: <INSIDE_VALUE_TYPE> = Default::default();
+ __unit_map.read(&key_str, &mut __tmp_key);
+ __unit_map.read(&value_str, &mut __tmp_value);
+ self.insert(__tmp_key, __tmp_value);
+ }
+ </MAP?>
+ }
+ fn read_unitmap(&mut self, name: String, unit_map: &UnitMap) {
+ match unit_map.lookup(name.as_str()) {
+ Some(unit) => {
+ if unit.get_type().ne(&"<TYPE_ID>") {
+ error!("type({}) is not <TYPE>", unit.get_type());
+ return;
+ }
+
+ unit.read(self);
+ }
+ None => {
+ error!("Failed to find {}", name);
+ return;
+ }
+ }
+ }
+}
+</META_PARCELS!>
+
+)__rs_cb";
+
+#endif // IDLC_GEN_VERSION2_RS_GEN_BASE_CB_H_
--- /dev/null
+/*
+ * Copyright (c) 2024 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "idlc/gen/version2/rs_group_gen.h"
+
+#include <algorithm>
+
+namespace {
+#include "idlc/gen/version2/rs_group_gen_cb.h"
+}
+
+namespace tidl {
+namespace version2 {
+
+RsGroupGen::RsGroupGen(std::shared_ptr<Document> doc) : RsGeneratorBase(doc) {}
+
+void RsGroupGen::OnInitGen(std::ofstream& stream) {
+ RsGeneratorBase::OnInitGen(stream);
+ stream.open(FileName + "/mod.rs");
+ ReplaceAll(::CB_GROUP_MAIN)
+ .Replace("VERSION", std::string(FULLVER))
+ .Repeat("STRUCTS", GetDocument().GetBlocks(),
+ [&](ReplaceAll& ra, const std::shared_ptr<Block>& i) {
+ return SetStructs(ra, i);
+ })
+ .ReplaceBlock("MODULE_BLOCK", [&](ReplaceAll& ra) { SetModules(ra); })
+ .Out(stream);
+ stream.close();
+}
+
+void RsGroupGen::OnFiniGen(std::ofstream& stream) {
+ RsGeneratorBase::OnFiniGen(stream);
+}
+
+void RsGroupGen::SetModules(ReplaceAll& ra) {
+ std::string str;
+ int m_cnt = 2;
+ int d_cnt = 1;
+
+ ra.Repeat("MODULES", GetDocument().GetBlocks(),
+ [&](ReplaceAll& ra, const std::shared_ptr<Block>& i) {
+ if (i->GetType() != Block::TYPE_INTERFACE)
+ return false;
+ Interface& iface = static_cast<Interface&>(*i);
+ ra.Replace("MOD_NAME", PascalToSnake(iface.GetID()))
+ .Repeat("METHOD_ID", iface.GetDeclarations(),
+ [&](ReplaceAll& ra, const std::unique_ptr<Declaration>& d){
+ return SetMethodIDs(ra, d, m_cnt);
+ })
+ .Repeat("DELEGATE_ID", iface.GetDeclarations(),
+ [&](ReplaceAll& ra, const std::unique_ptr<Declaration>& d){
+ return SetDelegateIDs(ra, d, d_cnt);
+ })
+ .ReplaceBlock("DELEGATE_BLOCK", [&](ReplaceAll& ra) {
+ SetDelegateBlock(ra, iface);
+ })
+ .Repeat("ENUM", iface.GetEnums(),
+ [&](ReplaceAll& ra, const std::unique_ptr<Enum>& e) {
+ return SetEnum(ra, e);
+ })
+ .ReplaceBlock("INTERFACE_BLOCK", [&](ReplaceAll& ra) {
+ SetInterfaceBlock(ra, iface);
+ });
+ return true;
+ });
+}
+
+bool RsGroupGen::SetMethodIDs(ReplaceAll& ra,
+ const std::unique_ptr<Declaration>& d, int& cnt) {
+ if (d->GetMethodType() == Declaration::MethodType::DELEGATE)
+ return false;
+
+ ra.Replace("ID", SnakeToPascal(d->GetID()))
+ .Replace("COUNT", std::to_string(cnt++));
+ return true;
+}
+
+bool RsGroupGen::SetDelegateIDs(ReplaceAll& ra,
+ const std::unique_ptr<Declaration>& d, int& cnt) {
+ if (d->GetMethodType() != Declaration::MethodType::DELEGATE)
+ return false;
+
+ ra.Replace("ID", SnakeToPascal(d->GetID()))
+ .Replace("COUNT", std::to_string(cnt++));
+ return true;
+}
+
+
+void RsGroupGen::SetDelegateBlock(ReplaceAll& ra, const Interface& iface) {
+ auto& decls = iface.GetDeclarations();
+
+ ra.Repeat("DELEGATES", decls,
+ [&](ReplaceAll& ra, const std::unique_ptr<Declaration>& i) {
+ if (i->GetMethodType() != Declaration::MethodType::DELEGATE)
+ return false;
+ ra.Replace("TYPES", GetParameters(i->GetParameters(), true))
+ .Repeat("REPLY_BODY", i->GetParameters(),
+ [&](ReplaceAll& ra, const std::unique_ptr<tidl::Parameter>& p) {
+ ra.Replace("ID", p->GetID());
+ return true;
+ })
+ .Replace("METHOD_NAME", SnakeToPascal(i->GetID()))
+ .Replace("METHOD_ORG_NAME", i->GetID());
+ return true;
+ });
+}
+
+void RsGroupGen::SetInterfaceBlock(ReplaceAll& ra, const Interface& iface) {
+ ra.Repeat("ENUM", iface.GetEnums(),
+ [&](ReplaceAll& ra, const std::unique_ptr<Enum>& e) {
+ return SetEnum(ra, e);
+ });
+
+ ra.Replace("IFACE_NAME", SnakeToPascal(iface.GetID()))
+ .Repeat("METHODS_PROTO", iface.GetDeclarations(),
+ [&](ReplaceAll& ra, const std::unique_ptr<Declaration>& d){
+ return SetMethod(ra, d);
+ })
+ .Repeat("METHODS", iface.GetDeclarations(),
+ [&](ReplaceAll& ra, const std::unique_ptr<Declaration>& d){
+ return SetMethod(ra, d);
+ })
+ .Repeat("DISPATCHES", iface.GetDeclarations(),
+ [&](ReplaceAll& ra, const std::unique_ptr<Declaration>& d) {
+ if (d->GetMethodType() == Declaration::MethodType::DELEGATE)
+ return false;
+
+ ra.Replace("ID", d->GetID())
+ .Replace("SNAKE_ID", PascalToSnake(d->GetID()));
+ return true;
+ })
+ .Repeat("PRIVILEGES", iface.GetDeclarations(),
+ [&](ReplaceAll& ra, const std::unique_ptr<Declaration>& d) {
+ if (d->GetMethodType() == Declaration::MethodType::DELEGATE)
+ return false;
+
+ std::vector<std::string> privileges;
+ for (auto& attr : d->GetAttributes()) {
+ if (attr->GetKey() != "privilege")
+ continue;
+
+ privileges.push_back(attr->GetValue());
+ }
+ if (privileges.empty())
+ return false;
+
+ ra.Repeat("PRIVILEGE", privileges,
+ [&](ReplaceAll& ra, const std::string& priv) {
+ ra.Replace("ID", priv);
+ return true;
+ })
+ .Replace("METHOD", SnakeToPascal(d->GetID()));
+ return true;
+ });
+}
+
+bool RsGroupGen::SetMethod(ReplaceAll& ra, const std::unique_ptr<Declaration>& d) {
+ if (d->GetMethodType() == Declaration::MethodType::DELEGATE)
+ return false;
+
+ if (!d->GetComments().empty())
+ ra.Replace("COMMENTS", AddIndent(2 * TAB_SIZE, d->GetComments()));
+ else
+ ra.Replace("COMMENTS", {});
+
+ ra.Replace("FN_NAME", PascalToSnake(d->GetID()))
+ .Replace("PARAMS", GetParameters(d->GetParameters()))
+ // .Replace("RET", GetRetExpr(*d))
+ .Remove("ASYNC", (*d).GetMethodType() == Declaration::MethodType::SYNC)
+ .Remove("SYNC", (*d).GetMethodType() == Declaration::MethodType::ASYNC)
+ .Replace("METHOD_ID", SnakeToPascal((*d).GetID()))
+ .Repeat("REPLY_BODY", (*d).GetParameters(),
+ [&](ReplaceAll& ra, const std::unique_ptr<tidl::Parameter>& i) {
+ return SetSenderBody(ra, i);
+ })
+ .Repeat("SENDER_BODY", (*d).GetParameters(),
+ [&](ReplaceAll& ra, const std::unique_ptr<tidl::Parameter>& i) {
+ return SetSenderBody(ra, i);
+ })
+ .Repeat("RECEIVER_BODY", (*d).GetParameters(),
+ [&](ReplaceAll& ra, const std::unique_ptr<tidl::Parameter>& p) {
+ if (p->GetParameterType().GetBaseType().IsDelegateType())
+ return false;
+ ra.Replace("ID", p->GetID())
+ .Replace("TYPE", ConvertTypeToString(
+ p->GetParameterType().GetBaseType()));
+ return true;
+ })
+ .Repeat("DELEGATER_RECEIVER_BODY", (*d).GetParameters(),
+ [&](ReplaceAll& ra, const std::unique_ptr<tidl::Parameter>& p) {
+ if (!p->GetParameterType().GetBaseType().IsDelegateType())
+ return false;
+ ra.Replace("ID", p->GetID())
+ .Replace("TYPE", ConvertTypeToString(
+ p->GetParameterType().GetBaseType()));
+ return true;
+ })
+ .Repeat("RETURNS", (*d).GetParameters(),
+ [&](ReplaceAll& ra, const std::unique_ptr<tidl::Parameter>& p) {
+ if (p->GetParameterType().GetDirection() == ParameterType::Direction::IN ||
+ p->GetParameterType().GetBaseType().IsDelegateType())
+ return false;
+
+ ra.Replace("ID", p->GetID());
+ return true;
+ })
+ .Replace("IDS", GetParameterIDsWithDir((*d).GetParameters()))
+ .Replace("TYPE", [&]() { return ConvertTypeToString((*d).GetType()); });
+ return true;
+}
+
+void RsGroupGen::SetFile(ReplaceAll& ra,
+ const std::unique_ptr<tidl::Parameter>& i) {
+ std::string type = GetFullNameFromType(i->GetParameterType().GetBaseType());
+
+ ra.Remove("FILE", type != "file")
+ .Remove("FILESLIST", type != "list_file")
+ .Remove("FILESARRAY", type != "array_file");
+}
+
+bool RsGroupGen::SetSenderBody(ReplaceAll& ra,
+ const std::unique_ptr<tidl::Parameter>& i) {
+ if (i->GetParameterType().GetDirection() == ParameterType::Direction::OUT)
+ return false;
+
+ SetFile(ra, i);
+
+ ra.Replace("ID", i->GetID());
+ return true;
+}
+
+bool RsGroupGen::SetReceiverBody(ReplaceAll& ra,
+ const std::unique_ptr<tidl::Parameter>& i) {
+ if (i->GetParameterType().GetDirection() == ParameterType::Direction::IN)
+ return false;
+ ra.Replace("ID", i->GetID());
+ return true;
+}
+
+std::string RsGroupGen::GetRetExpr(const Declaration& decl) {
+ if (decl.GetType().ToString() == "void")
+ return "";
+ return "-> " + ConvertTypeToString(decl.GetType());
+}
+
+} // namespace version2
+} // namespace tidl
--- /dev/null
+/*
+ * Copyright (c) 2024 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef IDLC_RS_GEN_RS_GROUP_GEN_H_
+#define IDLC_RS_GEN_RS_GROUP_GEN_H_
+
+#include <memory>
+#include <string>
+
+#include "idlc/gen/version2/rs_gen_base.h"
+
+namespace tidl {
+namespace version2 {
+
+class RsGroupGen : public RsGeneratorBase {
+ public:
+ explicit RsGroupGen(std::shared_ptr<Document> doc);
+ virtual ~RsGroupGen() = default;
+
+ void OnInitGen(std::ofstream& stream) override;
+ void OnFiniGen(std::ofstream& stream) override;
+
+ private:
+ void SetModules(ReplaceAll& ra);
+ void SetDelegateBlock(ReplaceAll& ra, const Interface& iface);
+ void SetInterfaceBlock(ReplaceAll& ra, const Interface& iface);
+ bool SetMethod(ReplaceAll& ra, const std::unique_ptr<Declaration>& d);
+ std::string GetRetExpr(const Declaration& decl);
+ bool SetSenderBody(ReplaceAll& ra,
+ const std::unique_ptr<tidl::Parameter>& i);
+ bool SetReceiverBody(ReplaceAll& ra,
+ const std::unique_ptr<tidl::Parameter>& i);
+ bool SetMethodIDs(ReplaceAll& ra,
+ const std::unique_ptr<Declaration>& d, int& cnt);
+ bool SetDelegateIDs(ReplaceAll& ra,
+ const std::unique_ptr<Declaration>& d, int& cnt);
+ void SetFile(ReplaceAll& ra,
+ const std::unique_ptr<tidl::Parameter>& i);
+};
+
+} // namespace version2
+} // namespace tidl
+
+#endif // IDLC_RS_GEN_RS_GROUP_GEN_H_
--- /dev/null
+/*
+ * Copyright (c) 2024 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef IDLC_RS_GEN_RS_GROUP_GEN_CB_H_
+#define IDLC_RS_GEN_RS_GROUP_GEN_CB_H_
+
+constexpr const char CB_GROUP_MAIN[] =
+R"__rs_cb(
+extern crate rust_app_event;
+extern crate rust_rpc_port;
+use rust_app_event::{AppEvent, Bundle};
+use rust_rpc_port::parcel::Parcel;
+use std::collections::{LinkedList, HashMap, HashSet};
+use std::sync::{Arc, Mutex};
+
+use impl_internal::*;
+#[macro_use]
+mod impl_internal;
+
+const TIDL_VERSION: &str = "<VERSION>";
+
+#[derive(PartialEq, Debug)]
+pub enum ErrorId {
+ IoError = -5,
+ OutOfMemory = -12,
+ PermissionDenied = -13,
+ InvalidParameter = -22,
+}
+
+fn convert_err(id: i32) -> ErrorId {
+ match id {
+ -5 => ErrorId::IoError,
+ -12 => ErrorId::OutOfMemory,
+ -13 => ErrorId::PermissionDenied,
+ -22 => ErrorId::InvalidParameter,
+ _ => {
+ error!("Unknown error {:?}", ErrorId::IoError);
+ ErrorId::IoError
+ }
+ }
+}
+
+<STRUCTS*>
+pub mod <STRUCT_MOD_NAME> {
+ use super::*;
+ <ENUM*>
+ #[derive(Copy, Clone)]
+ pub enum <ENUM_NAME> {
+ <PROPERTIES*>
+ <ID>,
+ </PROPERTIES*>
+ DEFAULT
+ }
+ impl Default for <ENUM_NAME> {
+ fn default() -> Self {
+ <ENUM_NAME>::DEFAULT
+ }
+ }
+
+ </ENUM*>
+ #[derive(Default)]
+ pub struct <STRUCT_NAME> {
+ <PROPERTIES*>
+ pub <ID>: <TYPE>,
+ </PROPERTIES*>
+ }
+}
+</STRUCTS*>
+
+<MODULE_BLOCK!>
+<MODULES*>
+pub mod <MOD_NAME> {
+ use super::super::*;
+ use super::*;
+
+ #[derive(PartialEq)]
+ enum MethodId {
+ __Result = 0,
+ __Callback = 1,
+ <METHOD_ID*>
+ <ID> = <COUNT>,
+ </METHOD_ID*>
+ }
+
+ #[derive(PartialEq)]
+ enum DelegateId {
+ <DELEGATE_ID*>
+ <ID> = <COUNT>,
+ </DELEGATE_ID*>
+ }
+
+ <INTERFACE_BLOCK!>
+ <ENUM*>
+ #[derive(Copy, Clone)]
+ pub enum <ENUM_NAME> {
+ <PROPERTIES*>
+ <ID>,
+ </PROPERTIES*>
+ DEFAULT
+ }
+ impl Default for <ENUM_NAME> {
+ fn default() -> Self {
+ <ENUM_NAME>::DEFAULT
+ }
+ }
+ </ENUM*>
+
+ pub struct Connection {
+ event_name: String,
+ group: Option<AppEvent>,
+ }
+
+ impl Connection {
+
+ /// <summary>
+ /// Unsubscribes the event.
+ /// </summary>
+ pub fn unsubscribe(&mut self) {
+ self.group = None;
+ }
+ }
+
+ pub trait ServiceHandler {
+
+ /// <summary>
+ /// The method for making service instances
+ /// </summary>
+ /// <param name="connection">The connection object</param>
+ fn new(connection: Arc<Mutex<Connection>>) -> Box<dyn ServiceHandler + Send> where Self: Sized;
+ <METHODS_PROTO*>
+ fn on_<FN_NAME>(&mut self, <PARAMS>);
+ </METHODS_PROTO*>
+ }
+
+ pub struct <IFACE_NAME> {
+ sender_id: String,
+ is_system: bool,
+ connection: Arc<Mutex<Connection>>,
+ handler: Box<dyn ServiceHandler + Send>,
+ on_received: Arc<Mutex<Box<dyn FnMut(&str, &Bundle) + Send>>>,
+ }
+
+ impl <IFACE_NAME> {
+
+ /// <summary>
+ /// Constructor for this struct
+ /// </summary>
+ /// <param name="sender_id">The sender application ID</param>
+ /// <param name="is_system">The flag indicating whether the event is a system event.</param>
+ pub fn new<T: ServiceHandler>(sender_id: String, is_system: bool) -> Arc<Mutex<<IFACE_NAME>>> {
+ let mut event_name: String;
+ match is_system {
+ true => event_name = "tizen.system.event.tidl_iface_<IFACE_NAME>".to_string(),
+ false => event_name = ("event.".to_owned() + &sender_id + ".tidl_iface_<IFACE_NAME>").to_string(),
+ }
+
+ let connection = Arc::new(Mutex::new(Connection {
+ event_name,
+ group: None,
+ }));
+ let mut obj = Arc::new(Mutex::new(Self {
+ sender_id,
+ is_system,
+ connection: connection.clone(),
+ handler: T::new(connection),
+ on_received: Arc::new(Mutex::new(Box::new(|event_name: &str, event_data: &Bundle| {
+ }))),
+ }));
+
+ let mut copy_obj = obj.clone();
+ obj.lock().unwrap().on_received = Arc::new(Mutex::new(Box::new(move |event_name: &str, event_data: &Bundle| {
+ let mut __parcel = copy_obj.lock().unwrap().get_parcel_from_bundle(event_data);
+ let mut __unit_map = UnitMap::new();
+ __unit_map.deserialize(&__parcel);
+ let mut __cmd: i32 = -1;
+ __cmd.read_unitmap("[METHOD]".to_string(), &mut __unit_map);
+ match __cmd {
+ <DISPATCHES*>
+ x if x == MethodId::<ID> as i32 => {
+ copy_obj.lock().unwrap().dispatch_<SNAKE_ID>(&__unit_map);
+ }
+ </DISPATCHES*>
+ _ => {
+ error!("Unknown command: {}", __cmd);
+ return;
+ }
+ }
+ })));
+
+ obj
+ }
+
+ fn get_bundle_from_parcel(&self, parcel: &Parcel) -> Bundle {
+ let mut raw = parcel.get_raw();
+ let mut b = Bundle::new();
+
+ b.add_bytes("TIDL_RAW", &raw.to_vec());
+ b
+ }
+
+ fn get_parcel_from_bundle(&self, bundle: &Bundle) -> Parcel {
+ let mut raw = bundle.get_bytes("TIDL_RAW").unwrap();
+
+ Parcel::from_raw(raw.as_slice())
+ }
+
+ /// <summary>
+ /// Subscribes the event
+ /// </summary>
+ pub fn subscribe(&mut self) -> Result<(), ErrorId> {
+ let mut connection = self.connection.lock().unwrap();
+ if connection.group.is_some() {
+ return Err(ErrorId::IoError);
+ }
+
+ connection.group = Some(AppEvent::new(connection.event_name.clone()));
+ if let Err(e) = connection.group.as_mut().unwrap().on_received(self.on_received.clone()) {
+ error!("failed to subscribe event: {:?}", e);
+ return Err(convert_err(e as i32));
+ }
+
+ Ok(())
+ }
+
+ /// <summary>
+ /// Unsubscribes the event
+ /// </summary>
+ pub fn unsubscribe(&mut self) {
+ self.connection.lock().unwrap().unsubscribe();
+ }
+
+ <METHODS*>
+ pub fn <FN_NAME>(&mut self, <PARAMS>) -> Result<(), ErrorId> {
+ let mut __unit_map = UnitMap::new();
+ (MethodId::<METHOD_ID> as i32).write_unitmap("[METHOD]", &mut __unit_map);
+ <SENDER_BODY*>
+ <ID>.write_unitmap("<ID>", &mut __unit_map);
+ </SENDER_BODY*>
+
+ let mut __parcel = Parcel::new();
+ __unit_map.serialize(&mut __parcel);
+ let mut __bundle = self.get_bundle_from_parcel(&__parcel);
+
+ let connection = self.connection.lock().unwrap();
+ match AppEvent::publish(connection.event_name.as_str(), &mut __bundle) {
+ Ok(_) => Ok(()),
+ Err(e) => {
+ error!("fail to publish");
+ Err(convert_err(e as i32))
+ },
+ }
+ }
+
+ fn dispatch_<FN_NAME>(&mut self, unit_map: &UnitMap) {
+ <RECEIVER_BODY*>
+ let mut <ID>: <TYPE> = Default::default();
+ unit_map.read("<ID>", &mut <ID>);
+ </RECEIVER_BODY*>
+ self.handler.on_<FN_NAME>(<IDS>);
+ }
+ </METHODS*>
+ }
+ </INTERFACE_BLOCK!>
+}
+</MODULES*>
+</MODULE_BLOCK!>
+)__rs_cb";
+
+#endif // IDLC_RS_GEN_RS_GROUP_GEN_CB_H_
--- /dev/null
+/*
+ * Copyright (c) 2024 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "idlc/gen/version2/rs_proxy_gen.h"
+
+namespace {
+#include "idlc/gen/version2/rs_proxy_gen_cb.h"
+}
+
+namespace tidl {
+namespace version2 {
+
+RsProxyGen::RsProxyGen(std::shared_ptr<Document> doc)
+ : RsGeneratorBase(doc) {}
+
+void RsProxyGen::OnInitGen(std::ofstream& stream) {
+ RsGeneratorBase::OnInitGen(stream);
+ stream.open(FileName + "/mod.rs");
+ ReplaceAll(::CB_PROXY_MAIN)
+ .Replace("VERSION", std::string(FULLVER))
+ .Repeat("STRUCTS", GetDocument().GetBlocks(),
+ [&](ReplaceAll& ra, const std::shared_ptr<Block>& i) {
+ return SetStructs(ra, i);
+ })
+ .ReplaceBlock("MODULE_BLOCK", [&](ReplaceAll& ra) { SetModules(ra); })
+ .Remove("BUNDLE_HEADER_BLOCK", RsGeneratorBase::HasBundle() != true)
+ .Out(stream);
+ stream.close();
+}
+
+void RsProxyGen::OnFiniGen(std::ofstream& stream) {
+ RsGeneratorBase::OnFiniGen(stream);
+}
+
+void RsProxyGen::SetModules(ReplaceAll& ra) {
+ std::string str;
+ int m_cnt = 2;
+ int d_cnt = 1;
+
+ ra.Repeat("MODULES", GetDocument().GetBlocks(),
+ [&](ReplaceAll& ra, const std::shared_ptr<Block>& i) {
+ if (i->GetType() != Block::TYPE_INTERFACE)
+ return false;
+ Interface& iface = static_cast<Interface&>(*i);
+ ra.Replace("MOD_NAME", PascalToSnake(iface.GetID()))
+ .Repeat("METHOD_ID", iface.GetDeclarations(),
+ [&](ReplaceAll& ra, const std::unique_ptr<Declaration>& d){
+ return SetMethodIDs(ra, d, m_cnt);
+ })
+ .Repeat("DELEGATE_ID", iface.GetDeclarations(),
+ [&](ReplaceAll& ra, const std::unique_ptr<Declaration>& d){
+ return SetDelegateIDs(ra, d, d_cnt);
+ })
+ .ReplaceBlock("DELEGATE_BLOCK", [&](ReplaceAll& ra) {
+ SetDelegateBlock(ra, iface);
+ })
+ .Repeat("ENUM", iface.GetEnums(),
+ [&](ReplaceAll& ra, const std::unique_ptr<Enum>& e) {
+ return SetEnum(ra, e);
+ })
+ .ReplaceBlock("INTERFACE_BLOCK", [&](ReplaceAll& ra) {
+ SetInterfaceBlock(ra, iface);
+ });
+ return true;
+ });
+}
+
+bool RsProxyGen::SetMethodIDs(ReplaceAll& ra,
+ const std::unique_ptr<Declaration>& d, int& cnt) {
+ if (d->GetMethodType() == Declaration::MethodType::DELEGATE)
+ return false;
+
+ ra.Replace("ID", SnakeToPascal(d->GetID()))
+ .Replace("COUNT", std::to_string(cnt++));
+ return true;
+}
+
+bool RsProxyGen::SetDelegateIDs(ReplaceAll& ra,
+ const std::unique_ptr<Declaration>& d, int& cnt) {
+ if (d->GetMethodType() != Declaration::MethodType::DELEGATE)
+ return false;
+
+ ra.Replace("ID", SnakeToPascal(d->GetID()))
+ .Replace("COUNT", std::to_string(cnt++));
+ return true;
+}
+
+
+void RsProxyGen::SetDelegateBlock(ReplaceAll& ra, const Interface& iface) {
+ auto& decls = iface.GetDeclarations();
+
+ ra.Repeat("DELEGATES", decls,
+ [&](ReplaceAll& ra, const std::unique_ptr<Declaration>& i) {
+ if (i->GetMethodType() != Declaration::MethodType::DELEGATE)
+ return false;
+ ra.Replace("TYPES", GetParameters(i->GetParameters(), false))
+ .Repeat("RECEIVER_BODY", i->GetParameters(),
+ [&](ReplaceAll& ra, const std::unique_ptr<tidl::Parameter>& p){
+ ra.Replace("ID", p->GetID())
+ .Replace("TYPE", ConvertTypeToString(
+ p->GetParameterType().GetBaseType()));
+ return true;
+ })
+ .Replace("IDS", GetParameterIDs(i->GetParameters()))
+ .Replace("METHOD_NAME", SnakeToPascal(i->GetID()));
+ return true;
+ });
+}
+
+void RsProxyGen::SetInterfaceBlock(ReplaceAll& ra, const Interface& iface) {
+ ra.Repeat("ENUM", iface.GetEnums(),
+ [&](ReplaceAll& ra, const std::unique_ptr<Enum>& e) {
+ return SetEnum(ra, e);
+ });
+
+ ra.Replace("IFACE_NAME", iface.GetID())
+ .Repeat("METHODS", iface.GetDeclarations(),
+ [&](ReplaceAll& ra, const std::unique_ptr<Declaration>& d){
+ return SetMethod(ra, d);
+ });
+}
+
+bool RsProxyGen::SetMethod(ReplaceAll& ra, const std::unique_ptr<Declaration>& d) {
+ if (d->GetMethodType() == Declaration::MethodType::DELEGATE)
+ return false;
+
+ if (!d->GetComments().empty())
+ ra.Replace("COMMENTS", AddIndent(2 * TAB_SIZE, d->GetComments()));
+ else
+ ra.Replace("COMMENTS", {});
+
+ ra.Replace("FN_NAME", PascalToSnake(d->GetID()))
+ .Replace("PARAMS", GetParameters(d->GetParameters()))
+// .Replace("RET", GetRetExpr(*d))
+ .Replace("METHOD_ID", SnakeToPascal((*d).GetID()))
+ .Repeat("SENDER_BODY", (*d).GetParameters(),
+ [&](ReplaceAll& ra, const std::unique_ptr<tidl::Parameter>& i) {
+ return SetSenderBody(ra, i);
+ })
+ .Remove("ASYNC", (*d).GetMethodType() == Declaration::MethodType::SYNC)
+ .Remove("SYNC", (*d).GetMethodType() == Declaration::MethodType::ASYNC)
+ .Repeat("RECEIVER_BODY", (*d).GetParameters(),
+ [&](ReplaceAll& ra, const std::unique_ptr<tidl::Parameter>& i) {
+ return SetReceiverBody(ra, i);
+ })
+ .Repeat("REG_DELEGATERS", (*d).GetParameters(),
+ [&](ReplaceAll& ra, const std::unique_ptr<tidl::Parameter>& i) {
+ return SetRegDelegaters(ra, i);
+ })
+ .Remove("HAS_RETURN", (*d).GetType().ToString() == "void" )
+ .Replace("TYPE", [&]() {
+ return ConvertTypeToString((*d).GetType());
+ });
+ return true;
+}
+
+void RsProxyGen::SetFile(ReplaceAll& ra,
+ const std::unique_ptr<tidl::Parameter>& i) {
+ std::string type = GetFullNameFromType(i->GetParameterType().GetBaseType());
+
+ ra.Remove("FILE", type != "file")
+ .Remove("FILESLIST", type != "list_file")
+ .Remove("FILESARRAY", type != "array_file");
+}
+
+bool RsProxyGen::SetSenderBody(ReplaceAll& ra,
+ const std::unique_ptr<tidl::Parameter>& i) {
+ if (i->GetParameterType().GetDirection() == ParameterType::Direction::OUT)
+ return false;
+
+ SetFile(ra, i);
+
+ ra.Replace("ID", i->GetID());
+ return true;
+}
+
+bool RsProxyGen::SetReceiverBody(ReplaceAll& ra,
+ const std::unique_ptr<tidl::Parameter>& i) {
+ if (i->GetParameterType().GetDirection() == ParameterType::Direction::IN)
+ return false;
+ ra.Replace("ID", i->GetID());
+ return true;
+}
+
+bool RsProxyGen::SetRegDelegaters(ReplaceAll& ra,
+ const std::unique_ptr<tidl::Parameter>& i) {
+ if (!IsDelegateType(i->GetParameterType().GetBaseType()))
+ return false;
+ ra.Replace("ID", i->GetID());
+ return true;
+}
+
+std::string RsProxyGen::GetRetExpr(const Declaration& decl) {
+ if (decl.GetType().ToString() == "void")
+ return "";
+ return "-> " + ConvertTypeToString(decl.GetType());
+}
+
+} // namespace version2
+} // namespace tidl
--- /dev/null
+/*
+ * Copyright (c) 2024 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef IDLC_GEN_VERSION2_RS_PROXY_GEN_H_
+#define IDLC_GEN_VERSION2_RS_PROXY_GEN_H_
+
+#include <memory>
+#include <string>
+
+#include "idlc/gen/version2/rs_gen_base.h"
+
+namespace tidl {
+namespace version2 {
+
+class RsProxyGen : public RsGeneratorBase {
+ public:
+ explicit RsProxyGen(std::shared_ptr<Document> doc);
+ virtual ~RsProxyGen() = default;
+
+ void OnInitGen(std::ofstream& stream) override;
+ void OnFiniGen(std::ofstream& stream) override;
+
+ private:
+ void SetModules(ReplaceAll& ra);
+ void SetDelegateBlock(ReplaceAll& ra, const Interface& iface);
+ void SetInterfaceBlock(ReplaceAll& ra, const Interface& iface);
+ bool SetMethod(ReplaceAll& ra, const std::unique_ptr<Declaration>& d);
+ std::string GetRetExpr(const Declaration& decl);
+ bool SetSenderBody(ReplaceAll& ra,
+ const std::unique_ptr<tidl::Parameter>& i);
+ bool SetReceiverBody(ReplaceAll& ra,
+ const std::unique_ptr<tidl::Parameter>& i);
+ bool SetRegDelegaters(ReplaceAll& ra,
+ const std::unique_ptr<tidl::Parameter>& i);
+ bool SetMethodIDs(ReplaceAll& ra,
+ const std::unique_ptr<Declaration>& d, int& cnt);
+ bool SetDelegateIDs(ReplaceAll& ra,
+ const std::unique_ptr<Declaration>& d, int& cnt);
+ void SetFile(ReplaceAll& ra,
+ const std::unique_ptr<tidl::Parameter>& i);
+};
+
+} // namespace version2
+} // namespace tidl
+
+#endif // IDLC_RS_GEN_RS_PROXY_GEN_H_
--- /dev/null
+/*
+ * Copyright (c) 2024 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef IDLC_GEN_VERSION2_RS_PROXY_GEN_CB_H_
+#define IDLC_GEN_VERSION2_RS_PROXY_GEN_CB_H_
+
+constexpr const char CB_PROXY_MAIN[] =
+R"__rs_cb(
+extern crate rust_rpc_port;
+<BUNDLE_HEADER_BLOCK?>
+extern crate tizen_bundle;
+
+use tizen_bundle::tizen_bundle::Bundle;
+</BUNDLE_HEADER_BLOCK?>
+use rust_rpc_port::parcel::Parcel;
+use rust_rpc_port::proxy::{Proxy, Receive};
+use rust_rpc_port::{Port, PortType};
+use std::sync::{Arc, Mutex};
+use std::collections::{LinkedList, HashMap, HashSet};
+use std::sync::atomic::{AtomicI32, Ordering};
+
+use impl_internal::*;
+#[macro_use]
+mod impl_internal;
+
+static SEQ_NUM: AtomicI32 = AtomicI32::new(0);
+const TIDL_VERSION: &str = "<VERSION>";
+
+
+#[derive(PartialEq, Debug)]
+pub enum ErrorId {
+ IoError = -5,
+ OutOfMemory = -12,
+ PermissionDenied = -13,
+ InvalidParameter = -22,
+}
+
+fn convert_err(id: i32) -> ErrorId {
+ match id {
+ -5 => ErrorId::IoError,
+ -12 => ErrorId::OutOfMemory,
+ -13 => ErrorId::PermissionDenied,
+ -22 => ErrorId::InvalidParameter,
+ _ => {
+ error!("Unknown error {:?}", ErrorId::IoError);
+ ErrorId::IoError
+ }
+ }
+}
+
+#[derive(Debug, Clone)]
+pub struct RemoteException {
+ pub cause: i32,
+ pub message: String,
+}
+
+impl RemoteException {
+ pub fn new() -> Self {
+ RemoteException {
+ cause: 0,
+ message: "".to_string(),
+ }
+ }
+
+ pub fn with_message(message: &str) -> Self {
+ RemoteException {
+ cause: 0,
+ message: message.to_string(),
+ }
+ }
+
+ pub fn with_cause_and_message(cause: i32, message: &str) -> Self {
+ RemoteException {
+ cause,
+ message: message.to_string(),
+ }
+ }
+
+ pub fn get_cause(&self) -> i32 {
+ self.cause
+ }
+
+ pub fn get_message(&self) -> &String {
+ &self.message
+ }
+}
+
+#[derive(Debug)]
+pub enum Exception {
+ LocalException(ErrorId),
+ RemoteException(RemoteException),
+}
+
+<STRUCTS*>
+pub mod <STRUCT_MOD_NAME> {
+ use super::*;
+ <ENUM*>
+ #[derive(Copy, Clone)]
+ pub enum <ENUM_NAME> {
+ <PROPERTIES*>
+ <ID>,
+ </PROPERTIES*>
+ DEFAULT
+ }
+ impl Default for <ENUM_NAME> {
+ fn default() -> Self {
+ <ENUM_NAME>::DEFAULT
+ }
+ }
+
+ </ENUM*>
+ #[derive(Default)]
+ pub struct <STRUCT_NAME> {
+ <PROPERTIES*>
+ pub <ID>: <TYPE>,
+ </PROPERTIES*>
+ }
+}
+</STRUCTS*>
+
+<MODULE_BLOCK!>
+<MODULES*>
+pub mod <MOD_NAME> {
+ use super::*;
+
+ #[derive(PartialEq)]
+ enum MethodId {
+ __Result = 0,
+ __Callback = 1,
+ <METHOD_ID*>
+ <ID> = <COUNT>,
+ </METHOD_ID*>
+ }
+
+ #[derive(PartialEq)]
+ enum DelegateId {
+ <DELEGATE_ID*>
+ <ID> = <COUNT>,
+ </DELEGATE_ID*>
+ }
+
+ <DELEGATE_BLOCK!>
+ trait Delegate {
+ fn invoke(&self, unit_map: &UnitMap, id: i32, seq_id: i32) -> bool;
+ }
+
+ struct DelegateBase {
+ id: i32,
+ seq_id: i32,
+ once: bool,
+ }
+
+ impl Default for DelegateBase {
+ fn default() -> Self {
+ Self {
+ id: 0,
+ seq_id: 0,
+ once: false,
+ }
+ }
+ }
+
+ impl Writeable for DelegateBase {
+ fn write_parcel(&self, parcel: &mut Parcel) {
+ self.id.write_parcel(parcel);
+ self.seq_id.write_parcel(parcel);
+ self.once.write_parcel(parcel);
+ }
+ fn write_unit(&self, unit: &mut Unit) {
+ let mut __unit_map = UnitMap::new();
+ self.id.write_unitmap("id", &mut __unit_map);
+ self.seq_id.write_unitmap("seq_id", &mut __unit_map);
+ self.once.write_unitmap("once", &mut __unit_map);
+ __unit_map.serialize(unit.get_mut_parcel());
+ }
+ fn write_unitmap(&self, name: &str, unit_map: &mut UnitMap) {
+ let mut unit = Unit::new(String::from(name), String::from("delegate"));
+ unit.write(self);
+ unit_map.insert(String::from(name), unit);
+ }
+ }
+
+ impl Readable for DelegateBase {
+ fn read_parcel(&mut self, parcel: &Parcel) {
+ self.id.read_parcel(parcel);
+ self.seq_id.read_parcel(parcel);
+ self.once.read_parcel(parcel);
+ }
+ fn read_unit(&mut self, unit: &Unit) {
+ let mut __unit_map = UnitMap::new();
+ __unit_map.deserialize(unit.get_parcel());
+
+ let mut __tmp_id: i32 = Default::default();
+ __unit_map.read("id", &mut __tmp_id);
+ self.id = __tmp_id;
+ let mut __tmp_seq_id: i32 = Default::default();
+ __unit_map.read("seq_id", &mut __tmp_seq_id);
+ self.seq_id = __tmp_seq_id;
+ let mut __tmp_once: bool = Default::default();
+ __unit_map.read("once", &mut __tmp_once);
+ self.once = __tmp_once;
+ }
+ fn read_unitmap(&mut self, name: String, unit_map: &UnitMap) {
+ match unit_map.lookup(name.as_str()) {
+ Some(unit) => {
+ if unit.get_type().ne(&"delegate") {
+ error!("type({}) is not delegate", unit.get_type());
+ return;
+ }
+
+ unit.read(self);
+ }
+ None => {
+ error!("Failed to find {}", name);
+ return;
+ }
+ }
+ }
+ }
+
+ <DELEGATES*>
+ pub struct <METHOD_NAME><'a> {
+ base: DelegateBase,
+ callback: Box<dyn Fn(<TYPES>) + Send + 'a>
+ }
+
+ impl<'b> <METHOD_NAME><'b> {
+ pub fn new(once: bool) -> <METHOD_NAME><'b> {
+ Self {
+ base: DelegateBase {
+ id: DelegateId::<METHOD_NAME> as i32,
+ seq_id: SEQ_NUM.fetch_add(1, Ordering::SeqCst),
+ once,
+ },
+ callback: Box::new(|<IDS>|{})
+ }
+ }
+
+ fn write_unitmap(&self, name: &str, unit_map: &mut UnitMap) {
+ self.base.write_unitmap(name, unit_map);
+ }
+
+ pub fn on_received<F>(&mut self, handler: F)
+ where
+ F: Fn(<TYPES>) + Send + 'b,
+ {
+ self.callback = Box::new(handler);
+ }
+ }
+
+ impl Delegate for <METHOD_NAME><'_> {
+ fn invoke(&self, unit_map: &UnitMap, id: i32, seq_id: i32) -> bool {
+ if id != self.base.id || seq_id != self.base.seq_id {
+ return false;
+ }
+
+ <RECEIVER_BODY*>
+ let mut <ID>: <TYPE> = Default::default();
+ <ID>.read_unitmap("<ID>".to_string(), &unit_map);
+ </RECEIVER_BODY*>
+ let cb = &self.callback;
+ cb(<IDS>);
+ true
+ }
+ }
+ </DELEGATES*>
+ </DELEGATE_BLOCK!>
+
+ <INTERFACE_BLOCK!>
+ <ENUM*>
+ #[derive(Copy, Clone)]
+ pub enum <ENUM_NAME> {
+ <PROPERTIES*>
+ <ID>,
+ </PROPERTIES*>
+ DEFAULT
+ }
+ impl Default for <ENUM_NAME> {
+ fn default() -> Self {
+ <ENUM_NAME>::DEFAULT
+ }
+ }
+ </ENUM*>
+
+ pub struct <IFACE_NAME><'a> {
+ proxy: Arc<Mutex<Proxy<'a>>>,
+ delegate_list: Vec<Box<dyn Delegate + Send + 'a>>,
+ }
+
+ impl Receive for <IFACE_NAME><'_> {
+ fn on_received(&mut self, receiver: &str, port_name: &str) {
+ info!("receiver {receiver} port_name {port_name}");
+ self.on_received(receiver, port_name);
+ }
+ }
+
+ impl<'b> <IFACE_NAME><'b> {
+
+ /// <summary>
+ /// Constructor for this struct
+ /// </summary>
+ pub fn new() -> Arc<Mutex<<IFACE_NAME><'b>>> {
+ info!("proxy new");
+ let p = Arc::new(Mutex::new(Proxy::try_new().unwrap()));
+ let ret = Arc::new(Mutex::new(Self {
+ proxy: p.clone(),
+ delegate_list: vec![],
+ }));
+
+ p.lock().unwrap()
+ .on_received(ret.clone() as Arc<Mutex<dyn Receive + Send + 'b>>);
+ ret
+ }
+
+ /// <summary>
+ /// Connects to the service app.
+ /// </summary>
+ /// <privilege>http://tizen.org/privilege/appmanager.launch</privilege>
+ /// <privilege>http://tizen.org/privilege/datasharing</privilege>
+ /// <param name="appid">The service app ID to connect</param>
+ /// <exception cref="InvalidParameter">
+ /// Returns when the appid to connect is invalid.
+ /// </exception>
+ /// <exception cref="IoError">
+ /// Returns when internal I/O error happen.
+ /// </exception>
+ /// <exception cref="PermissionDenied">
+ /// Returns when the permission is denied.
+ /// </exception>
+ /// <remark> If you want to use this method, you must add privileges.</remark>
+ pub fn try_connect(&self, appid: &str) -> Result<(), ErrorId> {
+ info!("appid {appid}");
+ let result = self.proxy.lock().unwrap().try_connect(appid, "<IFACE_NAME>");
+ match result {
+ Ok(_) => Ok(()),
+ Err(id) => Err(convert_err(id))
+ }
+ }
+
+ /// <summary>
+ /// Connects to the service app synchornously.
+ /// </summary>
+ /// <privilege>http://tizen.org/privilege/appmanager.launch</privilege>
+ /// <privilege>http://tizen.org/privilege/datasharing</privilege>
+ /// <param name="appid">The service app ID to connect</param>
+ /// <exception cref="InvalidParameter">
+ /// Returns when the appid to connect is invalid.
+ /// </exception>
+ /// <exception cref="IoError">
+ /// Returns when internal I/O error happen.
+ /// </exception>
+ /// <exception cref="PermissionDenied">
+ /// Returns when the permission is denied.
+ /// </exception>
+ /// <remark> If you want to use this method, you must add privileges.</remark>
+ pub fn try_connect_sync(&self, appid: &str) -> Result<(), ErrorId> {
+ info!("appid {appid}");
+ let result = self.proxy.lock().unwrap().try_connect_sync(appid, "<IFACE_NAME>");
+ match result {
+ Ok(_) => Ok(()),
+ Err(id) => Err(convert_err(id))
+ }
+ }
+
+ /// <summary>
+ /// This method will be invoked when the client app is connected to the service app.
+ /// </summary>
+ /// <param name="handler">The handler to be invoked when the client app is connected</param>
+ pub fn on_connected<F>(&mut self, handler: F)
+ where
+ F: Fn(&str, &str, Port) + 'b,
+ {
+ self.proxy.lock().unwrap().on_connected(handler);
+ }
+
+ /// <summary>
+ /// This method will be invoked after the client app was disconnected from the service app.
+ /// </summary>
+ /// <param name="handler">The handler to be invoked when the client app is disconnected</param>
+ pub fn on_disconnected<F>(&mut self, handler: F)
+ where
+ F: Fn(&str, &str) + 'b,
+ {
+ self.proxy.lock().unwrap().on_disconnected(handler);
+ }
+
+ /// <summary>
+ /// This method will be invoked when the service app rejects the client app.
+ /// </summary>
+ /// <param name="handler">The handler to be invoked when the service app rejects the client app</param>
+ pub fn on_rejected<F>(&mut self, handler: F)
+ where
+ F: Fn(&str, &str) + 'b,
+ {
+ self.proxy.lock().unwrap().on_rejected(handler);
+ }
+
+ fn on_received(&mut self, receiver: &str, port_name: &str) {
+ info!("receiver {receiver} port_name {port_name}");
+ let __port = self.proxy.lock().unwrap().get_port(&PortType::Callback);
+ let __parcel_received = Parcel::from(&__port);
+
+ let mut __unit_map = UnitMap::new();
+ __unit_map.deserialize(&__parcel_received);
+ let mut __cmd: i32 = -1;
+ let unit = __unit_map.lookup("[METHOD]");
+ match unit {
+ Some(u) => {
+ u.read(&mut __cmd);
+ }
+ None => {
+ error!("Invalid protocol");
+ return;
+ }
+ }
+ let __cmd_exp = MethodId::__Callback as i32;
+ if __cmd != __cmd_exp {
+ error!("Invalid protocol");
+ return;
+ }
+
+ let mut __delegate_base: DelegateBase = DelegateBase::default();
+ __delegate_base.read_unitmap("delegate".to_string(), &mut __unit_map);
+ for (pos, delegate) in self.delegate_list.iter().enumerate() {
+ if delegate.invoke(&__unit_map, __delegate_base.id, __delegate_base.seq_id) {
+ if __delegate_base.once {
+ self.delegate_list.remove(pos);
+ }
+ break;
+ }
+ }
+ }
+
+ <METHODS*><COMMENTS>
+ pub fn <FN_NAME>(&mut self, <PARAMS>) -> Result<<TYPE>, Exception> {
+ let mut __p = Parcel::new();
+ __p.set_tag(String::from(TIDL_VERSION));
+ let seq_num = __p.get_seq_num();
+ info!("get seq_num {seq_num}");
+ let __port = self.proxy.lock().unwrap().get_port(&PortType::Main);
+
+ let mut __map = UnitMap::new();
+ (MethodId::<METHOD_ID> as i32).write_unitmap("[METHOD]", &mut __map);
+ <SENDER_BODY*>
+ <FILE?>
+ __port.set_private_sharing(&<ID>);
+ </FILE?>
+ <FILESLIST?>
+ let __vec_tmp: Vec<String> = <ID>.clone().into_iter().map(|s| s).collect();
+ __port.set_private_sharing_array(&__vec_tmp);
+ </FILESLIST?>
+ <FILESARRAY?>
+ __port.set_private_sharing_array(&<ID>);
+ </FILESARRAY?>
+ <ID>.write_unitmap("<ID>", &mut __map);
+ </SENDER_BODY*>
+ <REG_DELEGATERS*>
+ self.delegate_list.push(Box::new(<ID>));
+ </REG_DELEGATERS*>
+
+ __map.serialize(&mut __p);
+ let __r = __p.try_send(&__port);
+ if let Err(id) = __r {
+ error!("fail to send");
+ return Err(Exception::LocalException(convert_err(id)));
+ } <ASYNC?> else {
+ return Ok(());
+ }
+ </ASYNC?>
+
+ <SYNC?>
+ let mut __map_received = UnitMap::new();
+ loop {
+ let __parcel_received = Parcel::from(&__port);
+ if __parcel_received.get_seq_num() != seq_num {
+ continue;
+ }
+
+ __map_received.deserialize(&__parcel_received);
+ let mut cmd: i32 = -1;
+ __map_received.read("[METHOD]", &mut cmd);
+ let cmd_exp = MethodId::__Result as i32;
+ if cmd == cmd_exp {
+ break;
+ }
+ }
+
+ if __map_received.len() == 0 {
+ error!("received map size is zero");
+ }
+
+ if let Some(unit) = __map_received.lookup("[REMOTE_EXCEPTION]") {
+ let mut __remote_exception = RemoteException::new();
+ __remote_exception.read_unit(unit);
+ error!("seq_num {seq_num} exception {:?}", Exception::RemoteException(__remote_exception.clone()));
+ return Err(Exception::RemoteException(__remote_exception));
+ }
+
+ <RECEIVER_BODY*>
+ __map_received.read("<ID>", <ID>);
+ </RECEIVER_BODY*>
+ <HAS_RETURN?>
+ let mut __ret: <TYPE> = Default::default();
+ __map_received.read("[RESULT]", &mut __ret);
+ Ok(__ret)
+ </HAS_RETURN?>
+ </SYNC?>
+ }
+ </METHODS*>
+ }
+ </INTERFACE_BLOCK!>
+}
+</MODULES*>
+</MODULE_BLOCK!>
+)__rs_cb";
+
+#endif // IDLC_GEN_VERSION2_RS_PROXY_GEN_CB_H_
--- /dev/null
+/*
+ * Copyright (c) 2024 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "idlc/gen/version2/rs_stub_gen.h"
+
+#include <algorithm>
+
+namespace {
+#include "idlc/gen/version2/rs_stub_gen_cb.h"
+}
+
+namespace tidl {
+namespace version2 {
+
+RsStubGen::RsStubGen(std::shared_ptr<Document> doc,
+ std::shared_ptr<Options> options)
+ : RsGeneratorBase(doc), options_(std::move(options)) {}
+
+void RsStubGen::OnInitGen(std::ofstream& stream) {
+ RsGeneratorBase::OnInitGen(stream);
+ stream.open(FileName + "/mod.rs");
+ ReplaceAll(::CB_STUB_MAIN)
+ .Replace("VERSION", std::string(FULLVER))
+ .Repeat("STRUCTS", GetDocument().GetBlocks(),
+ [&](ReplaceAll& ra, const std::shared_ptr<Block>& i) {
+ return SetStructs(ra, i);
+ })
+ .ReplaceBlock("MODULE_BLOCK", [&](ReplaceAll& ra) { SetModules(ra); })
+ .Remove("BUNDLE_HEADER_BLOCK", RsGeneratorBase::HasBundle() != true)
+ .Out(stream);
+ stream.close();
+}
+
+void RsStubGen::OnFiniGen(std::ofstream& stream) {
+ RsGeneratorBase::OnFiniGen(stream);
+}
+
+void RsStubGen::SetModules(ReplaceAll& ra) {
+ std::string str;
+ int m_cnt = 2;
+ int d_cnt = 1;
+
+ ra.Repeat("MODULES", GetDocument().GetBlocks(),
+ [&](ReplaceAll& ra, const std::shared_ptr<Block>& i) {
+ if (i->GetType() != Block::TYPE_INTERFACE)
+ return false;
+ Interface& iface = static_cast<Interface&>(*i);
+ ra.Replace("MOD_NAME", PascalToSnake(iface.GetID()))
+ .Repeat("METHOD_ID", iface.GetDeclarations(),
+ [&](ReplaceAll& ra, const std::unique_ptr<Declaration>& d){
+ return SetMethodIDs(ra, d, m_cnt);
+ })
+ .Repeat("DELEGATE_ID", iface.GetDeclarations(),
+ [&](ReplaceAll& ra, const std::unique_ptr<Declaration>& d){
+ return SetDelegateIDs(ra, d, d_cnt);
+ })
+ .ReplaceBlock("DELEGATE_BLOCK", [&](ReplaceAll& ra) {
+ SetDelegateBlock(ra, iface);
+ })
+ .Repeat("ENUM", iface.GetEnums(),
+ [&](ReplaceAll& ra, const std::unique_ptr<Enum>& e) {
+ return SetEnum(ra, e);
+ })
+ .ReplaceBlock("INTERFACE_BLOCK", [&](ReplaceAll& ra) {
+ SetInterfaceBlock(ra, iface);
+ })
+ .RemoveAll("EXTENSION_BLOCK", options_->UseExtension() != true);
+ return true;
+ });
+}
+
+bool RsStubGen::SetMethodIDs(ReplaceAll& ra,
+ const std::unique_ptr<Declaration>& d, int& cnt) {
+ if (d->GetMethodType() == Declaration::MethodType::DELEGATE)
+ return false;
+
+ ra.Replace("ID", SnakeToPascal(d->GetID()))
+ .Replace("COUNT", std::to_string(cnt++));
+ return true;
+}
+
+bool RsStubGen::SetDelegateIDs(ReplaceAll& ra,
+ const std::unique_ptr<Declaration>& d, int& cnt) {
+ if (d->GetMethodType() != Declaration::MethodType::DELEGATE)
+ return false;
+
+ ra.Replace("ID", SnakeToPascal(d->GetID()))
+ .Replace("COUNT", std::to_string(cnt++));
+ return true;
+}
+
+
+void RsStubGen::SetDelegateBlock(ReplaceAll& ra, const Interface& iface) {
+ auto& decls = iface.GetDeclarations();
+
+ ra.Repeat("DELEGATES", decls,
+ [&](ReplaceAll& ra, const std::unique_ptr<Declaration>& i) {
+ if (i->GetMethodType() != Declaration::MethodType::DELEGATE)
+ return false;
+ ra.Replace("TYPES", GetParameters(i->GetParameters(), true))
+ .Repeat("REPLY_BODY", i->GetParameters(),
+ [&](ReplaceAll& ra, const std::unique_ptr<tidl::Parameter>& p) {
+ ra.Replace("ID", p->GetID());
+ return true;
+ })
+ .Replace("METHOD_NAME", SnakeToPascal(i->GetID()))
+ .Replace("METHOD_ORG_NAME", i->GetID());
+ return true;
+ });
+}
+
+void RsStubGen::SetInterfaceBlock(ReplaceAll& ra, const Interface& iface) {
+ ra.Repeat("ENUM", iface.GetEnums(),
+ [&](ReplaceAll& ra, const std::unique_ptr<Enum>& e) {
+ return SetEnum(ra, e);
+ });
+
+ ra.Replace("IFACE_NAME", iface.GetID())
+ .Repeat("METHODS_PROTO", iface.GetDeclarations(),
+ [&](ReplaceAll& ra, const std::unique_ptr<Declaration>& d){
+ return SetMethod(ra, d);
+ })
+ .Repeat("METHODS", iface.GetDeclarations(),
+ [&](ReplaceAll& ra, const std::unique_ptr<Declaration>& d){
+ return SetMethod(ra, d);
+ })
+ .Repeat("DISPATCHES", iface.GetDeclarations(),
+ [&](ReplaceAll& ra, const std::unique_ptr<Declaration>& d) {
+ if (d->GetMethodType() == Declaration::MethodType::DELEGATE)
+ return false;
+
+ ra.Replace("ID", d->GetID())
+ .Replace("SNAKE_ID", PascalToSnake(d->GetID()));
+ return true;
+ })
+ .Repeat("PRIVILEGES", iface.GetDeclarations(),
+ [&](ReplaceAll& ra, const std::unique_ptr<Declaration>& d) {
+ if (d->GetMethodType() == Declaration::MethodType::DELEGATE)
+ return false;
+
+ std::vector<std::string> privileges;
+ for (auto& attr : d->GetAttributes()) {
+ if (attr->GetKey() != "privilege")
+ continue;
+
+ privileges.push_back(attr->GetValue());
+ }
+ if (privileges.empty())
+ return false;
+
+ ra.Repeat("PRIVILEGE", privileges,
+ [&](ReplaceAll& ra, const std::string& priv) {
+ ra.Replace("ID", priv);
+ return true;
+ })
+ .Replace("METHOD", SnakeToPascal(d->GetID()));
+ return true;
+ })
+ .Repeat("INTERFACE_PRIVILEGES", iface.GetAttributes(),
+ [&](ReplaceAll& ra, const std::unique_ptr<tidl::Attribute>& attr) {
+ if (attr->GetKey() != "privilege")
+ return false;
+
+ ra.Replace("INTERFACE_PRIVILEGE", attr->GetValue());
+ return true;
+ }
+ )
+ .Remove("SET_TRUSTED", std::find_if(
+ iface.GetAttributes().begin(),
+ iface.GetAttributes().end(),
+ [](const auto& attr) {
+ return attr->GetKey() == "trusted" && attr->GetValue() == "true";
+ }) == iface.GetAttributes().end());
+}
+
+bool RsStubGen::SetMethod(ReplaceAll& ra, const std::unique_ptr<Declaration>& d) {
+ if (d->GetMethodType() == Declaration::MethodType::DELEGATE)
+ return false;
+
+ if (!d->GetComments().empty())
+ ra.Replace("COMMENTS", AddIndent(2 * TAB_SIZE, d->GetComments()));
+ else
+ ra.Replace("COMMENTS", {});
+
+ ra.Replace("FN_NAME", PascalToSnake(d->GetID()))
+ .Replace("PARAMS", GetParameters(d->GetParameters()))
+ // .Replace("RET", GetRetExpr(*d))
+ .Remove("ASYNC", (*d).GetMethodType() == Declaration::MethodType::SYNC)
+ .Remove("SYNC", (*d).GetMethodType() == Declaration::MethodType::ASYNC)
+ .Replace("METHOD_ID", SnakeToPascal((*d).GetID()))
+ .Repeat("REPLY_BODY", (*d).GetParameters(),
+ [&](ReplaceAll& ra, const std::unique_ptr<tidl::Parameter>& i) {
+ return SetSenderBody(ra, i);
+ })
+ .Repeat("RECEIVER_BODY", (*d).GetParameters(),
+ [&](ReplaceAll& ra, const std::unique_ptr<tidl::Parameter>& p) {
+ if (p->GetParameterType().GetBaseType().IsDelegateType())
+ return false;
+ ra.Remove("IS_OUT_DIR", p->GetParameterType().GetDirection() == ParameterType::Direction::OUT)
+ .Replace("ID", p->GetID())
+ .Replace("TYPE", ConvertTypeToString(
+ p->GetParameterType().GetBaseType()));
+ return true;
+ })
+ .Repeat("DELEGATER_RECEIVER_BODY", (*d).GetParameters(),
+ [&](ReplaceAll& ra, const std::unique_ptr<tidl::Parameter>& p) {
+ if (!p->GetParameterType().GetBaseType().IsDelegateType())
+ return false;
+ ra.Replace("ID", p->GetID())
+ .Replace("TYPE", ConvertTypeToString(
+ p->GetParameterType().GetBaseType()));
+ return true;
+ })
+ .Repeat("RETURNS", (*d).GetParameters(),
+ [&](ReplaceAll& ra, const std::unique_ptr<tidl::Parameter>& p) {
+ if (p->GetParameterType().GetDirection() == ParameterType::Direction::IN ||
+ p->GetParameterType().GetBaseType().IsDelegateType())
+ return false;
+
+ ra.Replace("ID", p->GetID());
+ return true;
+ })
+ .Replace("IDS", GetParameterIDsWithDir((*d).GetParameters()))
+ .Replace("TYPE", [&]() { return ConvertTypeToString((*d).GetType()); });
+ return true;
+}
+
+void RsStubGen::SetFile(ReplaceAll& ra,
+ const std::unique_ptr<tidl::Parameter>& i) {
+ std::string type = GetFullNameFromType(i->GetParameterType().GetBaseType());
+
+ ra.Remove("FILE", type != "file")
+ .Remove("FILESLIST", type != "list_file")
+ .Remove("FILESARRAY", type != "array_file");
+}
+
+bool RsStubGen::SetSenderBody(ReplaceAll& ra,
+ const std::unique_ptr<tidl::Parameter>& i) {
+ if (i->GetParameterType().GetDirection() == ParameterType::Direction::OUT)
+ return false;
+
+ SetFile(ra, i);
+
+ ra.Replace("ID", i->GetID());
+ return true;
+}
+
+bool RsStubGen::SetReceiverBody(ReplaceAll& ra,
+ const std::unique_ptr<tidl::Parameter>& i) {
+ if (i->GetParameterType().GetDirection() == ParameterType::Direction::IN)
+ return false;
+ ra.Replace("ID", i->GetID());
+ return true;
+}
+
+std::string RsStubGen::GetRetExpr(const Declaration& decl) {
+ if (decl.GetType().ToString() == "void")
+ return "";
+ return "-> " + ConvertTypeToString(decl.GetType());
+}
+
+} // namespace version2
+} // namespace tidl
--- /dev/null
+/*
+ * Copyright (c) 2024 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef IDLC_RS_GEN_RS_STUB_GEN_H_
+#define IDLC_RS_GEN_RS_STUB_GEN_H_
+
+#include <memory>
+#include <string>
+
+#include "idlc/gen/version2/rs_gen_base.h"
+#include "idlc/options.h"
+
+namespace tidl {
+namespace version2 {
+
+class RsStubGen : public RsGeneratorBase {
+ public:
+ explicit RsStubGen(std::shared_ptr<Document> doc,
+ std::shared_ptr<Options> Options);
+ virtual ~RsStubGen() = default;
+
+ void OnInitGen(std::ofstream& stream) override;
+ void OnFiniGen(std::ofstream& stream) override;
+
+ private:
+ void SetModules(ReplaceAll& ra);
+ void SetDelegateBlock(ReplaceAll& ra, const Interface& iface);
+ void SetInterfaceBlock(ReplaceAll& ra, const Interface& iface);
+ bool SetMethod(ReplaceAll& ra, const std::unique_ptr<Declaration>& d);
+ std::string GetRetExpr(const Declaration& decl);
+ bool SetSenderBody(ReplaceAll& ra,
+ const std::unique_ptr<tidl::Parameter>& i);
+ bool SetReceiverBody(ReplaceAll& ra,
+ const std::unique_ptr<tidl::Parameter>& i);
+ bool SetMethodIDs(ReplaceAll& ra,
+ const std::unique_ptr<Declaration>& d, int& cnt);
+ bool SetDelegateIDs(ReplaceAll& ra,
+ const std::unique_ptr<Declaration>& d, int& cnt);
+ void SetFile(ReplaceAll& ra,
+ const std::unique_ptr<tidl::Parameter>& i);
+
+ private:
+ std::shared_ptr<Options> options_;
+};
+
+} // namespace version2
+} // namespace tidl
+
+#endif // IDLC_RS_GEN_RS_STUB_GEN_H_
--- /dev/null
+/*
+ * Copyright (c) 2024 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef IDLC_RS_GEN_RS_STUB_GEN_CB_H_
+#define IDLC_RS_GEN_RS_STUB_GEN_CB_H_
+
+constexpr const char CB_STUB_MAIN[] =
+R"__rs_cb(
+extern crate rust_rpc_port;
+<BUNDLE_HEADER_BLOCK?>
+extern crate tizen_bundle;
+
+use tizen_bundle::tizen_bundle::Bundle;
+</BUNDLE_HEADER_BLOCK?>
+use rust_rpc_port::parcel::Parcel;
+use rust_rpc_port::stub::Stub;
+use rust_rpc_port::{Port, PortType};
+use std::collections::{LinkedList, HashMap, HashSet};
+use std::sync::{Arc, Mutex};
+use std::ffi::{c_char, c_void, CStr, CString};
+use std::sync::atomic::{AtomicI32, Ordering};
+
+use impl_internal::*;
+#[macro_use]
+mod impl_internal;
+
+#[link(name = "capi-appfw-app-manager")]
+extern "C" {
+ fn app_info_create(app_id: *const c_char, app_info: *mut *mut c_void) -> i32;
+ fn app_info_destroy(app_info: *mut c_void);
+ fn app_info_get_package(app_info: *mut c_void, package: *mut *mut c_char) -> i32;
+}
+
+#[link(name = "capi-appfw-package-manager")]
+extern "C" {
+ fn package_info_create(package: *const c_char, package_info: *mut *mut c_void) -> i32;
+ fn package_info_foreach_privilege_info(
+ package_info: *mut c_void,
+ callback: extern "C" fn(*const c_char, *mut c_void,) -> bool,
+ user_data: *mut c_void,
+ );
+ fn package_info_destroy(package_info: *mut c_void);
+}
+
+static SEQ_NUM: AtomicI32 = AtomicI32::new(0);
+const TIDL_VERSION: &str = "<VERSION>";
+
+#[derive(PartialEq, Debug)]
+pub enum ErrorId {
+ IoError = -5,
+ OutOfMemory = -12,
+ PermissionDenied = -13,
+ InvalidParameter = -22,
+}
+
+fn convert_err(id: i32) -> ErrorId {
+ match id {
+ -5 => ErrorId::IoError,
+ -12 => ErrorId::OutOfMemory,
+ -13 => ErrorId::PermissionDenied,
+ -22 => ErrorId::InvalidParameter,
+ _ => {
+ error!("Unknown error {:?}", ErrorId::IoError);
+ ErrorId::IoError
+ }
+ }
+}
+
+#[derive(Debug)]
+pub struct RemoteException {
+ pub cause: i32,
+ pub message: String,
+}
+
+impl RemoteException {
+ pub fn new() -> Self {
+ RemoteException {
+ cause: 0,
+ message: "".to_string(),
+ }
+ }
+
+ pub fn with_message(message: &str) -> Self {
+ RemoteException {
+ cause: 0,
+ message: message.to_string(),
+ }
+ }
+
+ pub fn with_cause_and_message(cause: i32, message: &str) -> Self {
+ RemoteException {
+ cause,
+ message: message.to_string(),
+ }
+ }
+
+ pub fn get_cause(&self) -> i32 {
+ self.cause
+ }
+
+ pub fn get_message(&self) -> &String {
+ &self.message
+ }
+}
+
+#[derive(Debug)]
+pub enum Exception {
+ LocalException(ErrorId),
+ RemoteException(RemoteException),
+}
+
+<STRUCTS*>
+pub mod <STRUCT_MOD_NAME> {
+ use super::*;
+ <ENUM*>
+ #[derive(Copy, Clone)]
+ pub enum <ENUM_NAME> {
+ <PROPERTIES*>
+ <ID>,
+ </PROPERTIES*>
+ DEFAULT
+ }
+ impl Default for <ENUM_NAME> {
+ fn default() -> Self {
+ <ENUM_NAME>::DEFAULT
+ }
+ }
+
+ </ENUM*>
+ #[derive(Default)]
+ pub struct <STRUCT_NAME> {
+ <PROPERTIES*>
+ pub <ID>: <TYPE>,
+ </PROPERTIES*>
+ }
+}
+</STRUCTS*>
+
+<MODULE_BLOCK!>
+<MODULES*>
+pub mod <MOD_NAME> {
+ use super::super::*;
+ use super::*;
+
+ #[derive(PartialEq)]
+ enum MethodId {
+ __Result = 0,
+ __Callback = 1,
+ <METHOD_ID*>
+ <ID> = <COUNT>,
+ </METHOD_ID*>
+ }
+
+ #[derive(PartialEq)]
+ enum DelegateId {
+ <DELEGATE_ID*>
+ <ID> = <COUNT>,
+ </DELEGATE_ID*>
+ }
+
+ pub struct Peer {
+ sender: String,
+ instance: String,
+ port: Option<Port>,
+ }
+
+ impl Peer {
+
+ /// <summary>
+ /// Gets client app ID
+ /// </summary>
+ pub fn get_sender(&self) -> String {
+ self.sender.clone()
+ }
+
+ /// <summary>
+ /// Gets client instance ID
+ /// </summary>
+ pub fn get_instance(&self) -> String {
+ self.instance.clone()
+ }
+
+ <EXTENSION_BLOCK?>
+ pub fn get_pid(&self) -> Result<i32, ErrorId> {
+ match self.port.unwrap().get_peer_info() {
+ Ok((pid, uid)) => { Ok(pid) }
+ Err(id) => Err(convert_err(id))
+ }
+ }
+
+ pub fn get_uid(&self) -> Result<u32, ErrorId> {
+ match self.port.unwrap().get_peer_info() {
+ Ok((pid, uid)) => { Ok(uid) }
+ Err(id) => Err(convert_err(id))
+ }
+ }
+ </EXTENSION_BLOCK?>
+
+ fn set_port(&mut self, port: Port) {
+ self.port = Some(port);
+ }
+
+ /// <summary>
+ /// Disconnects from the client app
+ /// </summary>
+ /// <exception cref="IoError">
+ /// Returns when internal I/O error happen.
+ /// </exception>
+ pub fn disconnect(&mut self) -> Result<(), ErrorId> {
+ if self.port.is_none() {
+ return Ok(());
+ }
+
+ match self.port.unwrap().try_disconnect() {
+ Ok(_) => {
+ self.port = None;
+ Ok(())
+ }
+ Err(id) => Err(convert_err(id))
+ }
+ }
+ }
+
+ <DELEGATE_BLOCK!>
+ <DELEGATES*>
+ pub struct <METHOD_NAME> {
+ id: i32,
+ seq_id: i32,
+ once: bool,
+ callback_port: Arc<Port>,
+ valid: bool,
+ }
+
+ impl <METHOD_NAME> {
+ fn new(callback_port: Arc<Port>) -> Self {
+ Self {
+ id: DelegateId::<METHOD_NAME> as i32,
+ seq_id: SEQ_NUM.fetch_add(1, Ordering::SeqCst),
+ once: false,
+ callback_port,
+ valid: true,
+ }
+ }
+
+ pub fn invoke(&mut self, <TYPES>) -> Result<(), ErrorId> {
+ if self.once && !self.valid {
+ return Err(ErrorId::IoError);
+ }
+
+ let mut __unit_map = UnitMap::new();
+ (MethodId::__Callback as i32).write_unitmap("[METHOD]", &mut __unit_map);
+ self.write_unitmap("delegate", &mut __unit_map);
+ <REPLY_BODY*>
+ <ID>.write_unitmap("<ID>", &mut __unit_map);
+ </REPLY_BODY*>
+
+ let mut __parcel = Parcel::new();
+ __unit_map.serialize(&mut __parcel);
+ if let Err(err) = __parcel.try_send(&self.callback_port) {
+ error!("send failed: {:?}", err);
+ return Err(convert_err(err));
+ }
+
+ self.valid = false;
+ Ok(())
+ }
+ }
+
+ impl Writeable for <METHOD_NAME> {
+ fn write_parcel(&self, parcel: &mut Parcel) {
+ self.id.write_parcel(parcel);
+ self.seq_id.write_parcel(parcel);
+ self.once.write_parcel(parcel);
+ }
+ fn write_unit(&self, unit: &mut Unit) {
+ let mut __unit_map = UnitMap::new();
+ self.id.write_unitmap("id", &mut __unit_map);
+ self.seq_id.write_unitmap("seq_id", &mut __unit_map);
+ self.once.write_unitmap("once", &mut __unit_map);
+ __unit_map.serialize(unit.get_mut_parcel());
+ }
+ fn write_unitmap(&self, name: &str, unit_map: &mut UnitMap) {
+ let mut unit = Unit::new(String::from(name), String::from("delegate"));
+ unit.write(self);
+ unit_map.insert(String::from(name), unit);
+ }
+ }
+
+ impl Readable for <METHOD_NAME> {
+ fn read_parcel(&mut self, parcel: &Parcel) {
+ self.id.read_parcel(parcel);
+ self.seq_id.read_parcel(parcel);
+ self.once.read_parcel(parcel);
+ }
+ fn read_unit(&mut self, unit: &Unit) {
+ let mut __unit_map = UnitMap::new();
+ __unit_map.deserialize(unit.get_parcel());
+
+ let mut __tmp_id: i32 = Default::default();
+ __unit_map.read("id", &mut __tmp_id);
+ self.id = __tmp_id;
+ let mut __tmp_seq_id: i32 = Default::default();
+ __unit_map.read("seq_id", &mut __tmp_seq_id);
+ self.seq_id = __tmp_seq_id;
+ let mut __tmp_once: bool = Default::default();
+ __unit_map.read("once", &mut __tmp_once);
+ self.once = __tmp_once;
+ }
+ fn read_unitmap(&mut self, name: String, unit_map: &UnitMap) {
+ match unit_map.lookup(name.as_str()) {
+ Some(unit) => {
+ if unit.get_type().ne(&"delegate") {
+ error!("type({}) is not delegate", unit.get_type());
+ return;
+ }
+
+ unit.read(self);
+ }
+ None => {
+ error!("Failed to find {}", name);
+ return;
+ }
+ }
+ }
+ }
+ </DELEGATES*>
+ </DELEGATE_BLOCK!>
+
+ <INTERFACE_BLOCK!>
+ <ENUM*>
+ #[derive(Copy, Clone)]
+ pub enum <ENUM_NAME> {
+ <PROPERTIES*>
+ <ID>,
+ </PROPERTIES*>
+ DEFAULT
+ }
+ impl Default for <ENUM_NAME> {
+ fn default() -> Self {
+ <ENUM_NAME>::DEFAULT
+ }
+ }
+ </ENUM*>
+
+ pub trait ServiceHandler {
+
+ /// <summary>
+ /// The method for making service instances
+ /// </summary>
+ /// <param name="peer">The peer object</param>
+ fn new(peer: Arc<Mutex<Peer>>) -> Box<dyn ServiceHandler + Send> where Self: Sized;
+
+ /// <summary>
+ /// This method will be called when the client is connected
+ /// </summary>
+ fn on_create(&mut self);
+
+ /// <summary>
+ /// This method will be called when the client is disconnected
+ /// </summary>
+ fn on_terminate(&mut self);
+ <METHODS_PROTO*>
+ fn <FN_NAME>(&mut self, <PARAMS>) -> Result<<TYPE>, RemoteException>;
+ </METHODS_PROTO*>
+ }
+
+ struct Service {
+ peer: Arc<Mutex<Peer>>,
+ privilege_map: HashMap<i32, LinkedList<String>>,
+ privileges: HashSet<String>,
+ handler: Box<dyn ServiceHandler + Send>,
+ }
+
+ impl Service {
+ fn new<'a>(sender: &str, instance: &str, factory: &dyn Fn(Arc<Mutex<Peer>>) -> Box<dyn ServiceHandler + Send>) -> Self {
+ let peer = Arc::new(Mutex::new(Peer {
+ sender: sender.to_string(),
+ instance: instance.to_string(),
+ port: None,
+ }));
+
+ let mut service = Service {
+ peer: peer.clone(),
+ privilege_map: HashMap::new(),
+ privileges: HashSet::new(),
+ handler: (factory)(peer),
+ };
+
+ service.load_privileges();
+ service.set_privilege_map();
+ service
+ }
+
+ fn get_sender(&self) -> String {
+ self.peer.lock().unwrap().get_sender()
+ }
+
+ fn get_instance(&self) -> String {
+ self.peer.lock().unwrap().get_instance()
+ }
+
+ fn set_port(&mut self, port: Port) {
+ self.peer.lock().unwrap().set_port(port);
+ }
+
+ fn disconnect(&mut self) -> Result<(), ErrorId> {
+ info!("try disconnect");
+ self.peer.lock().unwrap().disconnect()
+ }
+
+ fn on_create(&mut self) {
+ self.handler.on_create();
+ }
+
+ fn on_terminate(&mut self) {
+ self.handler.on_terminate();
+ }
+
+ fn dispatch(&mut self, port: &Port, callback_port: Arc<Port>, parcel: &mut Parcel) {
+ let seq_num = parcel.get_seq_num();
+ let mut unit_map = UnitMap::new();
+ unit_map.deserialize(parcel);
+
+ let mut cmd: i32 = -1;
+ unit_map.read("[METHOD]", &mut cmd);
+
+ match cmd {
+ <DISPATCHES*>
+ x if x == MethodId::<ID> as i32 => {
+ self.dispatch_<SNAKE_ID>(port, callback_port, seq_num, &mut unit_map);
+ }
+ </DISPATCHES*>
+ _ => {
+ error!("Unknown command: {}", cmd);
+ return;
+ }
+ }
+ }
+
+ extern "C" fn privilege_info_cb(
+ privilege_name: *const c_char,
+ user_data: *mut c_void,
+ ) -> bool {
+ let mut service: &mut Service = unsafe { &mut *(user_data as *mut Service) };
+ let privilege = unsafe { CStr::from_ptr(privilege_name).to_str().unwrap() };
+ debug!("appid: {}, privilege: {}", service.get_sender(), &privilege);
+ service.privileges.insert(privilege.to_string());
+ return true;
+ }
+
+ fn load_privileges(&mut self) {
+ let mut app_info: *mut c_void = std::ptr::null_mut();
+ let sender = self.get_sender();
+ let ret = unsafe { app_info_create(CString::new(sender).unwrap().as_ptr() as *const c_char, &mut app_info) };
+ if ret != 0 {
+ error!("app_info_create failed. ret({})", ret);
+ return;
+ }
+
+ let mut package: *mut c_char = std::ptr::null_mut();
+ let ret = unsafe { app_info_get_package(app_info, &mut package) };
+ unsafe { app_info_destroy(app_info); }
+ if ret != 0 {
+ error!("Failed to get package. error({})", ret);
+ return;
+ }
+
+ let mut package_info: *mut c_void = std::ptr::null_mut();
+ let ret = unsafe { package_info_create(package, &mut package_info) };
+ unsafe { libc::free(package as *mut c_void); }
+ if ret != 0 {
+ error!("Failed to create package info. error({})", ret);
+ return;
+ }
+
+ let data = self as *mut _ as *mut c_void;
+ unsafe {
+ package_info_foreach_privilege_info(package_info, Self::privilege_info_cb, data);
+ package_info_destroy(package_info);
+ }
+ }
+
+ fn set_privilege_map(&mut self) {
+ <PRIVILEGES*>
+ let privileges: LinkedList<String> = LinkedList::from([
+ <PRIVILEGE*>
+ "<ID>".to_owned(),
+ </PRIVILEGE*>
+ ]);
+ self.privilege_map.insert(MethodId::<METHOD> as i32, privileges);
+ </PRIVILEGES*>
+ }
+
+ fn check_privileges(&self, method_id: i32) -> bool {
+ info!("method_id {method_id}");
+ match self.privilege_map.get(&method_id) {
+ Some(privileges) => {
+ for privilege in privileges {
+ if self.privileges.get(privilege).is_none() {
+ error!("{} does not exist", privilege);
+ return false;
+ }
+ }
+ true
+ }
+ None => true
+ }
+ }
+
+ <METHODS*>
+ fn dispatch_<FN_NAME>(&mut self, port: &Port, callback_port: Arc<Port>, seq_num: i32, unit_map: &UnitMap) {
+ let mut __map = UnitMap::new();
+ <SYNC?>
+ match self.check_privileges(MethodId::<METHOD_ID> as i32) {
+ false => {
+ error!("Permission denied");
+ let remote_except = RemoteException::with_cause_and_message(ErrorId::PermissionDenied as i32, "Permission denied");
+ remote_except.write_unitmap("[REMOTE_EXCEPTION]", &mut __map);
+ }
+ true => {
+ <RECEIVER_BODY*>
+ let mut <ID>: <TYPE> = Default::default();
+ <IS_OUT_DIR?>
+ unit_map.read("<ID>", &mut <ID>);
+ </IS_OUT_DIR?>
+ </RECEIVER_BODY*>
+ <DELEGATER_RECEIVER_BODY*>
+ let mut <ID> = <TYPE>::new(callback_port);
+ unit_map.read("<ID>", &mut <ID>);
+ </DELEGATER_RECEIVER_BODY*>
+ match self.handler.<FN_NAME>(<IDS>) {
+ Ok(ret) => {
+ ret.write_unitmap("[RESULT]", &mut __map);
+ <RETURNS*>
+ <ID>.write_unitmap("<ID>", &mut __map);
+ </RETURNS*>
+ }
+ Err(err) => {
+ error!("Error: cause({}), message({})", err.cause, err.message);
+ err.write_unitmap("[REMOTE_EXCEPTION]", &mut __map);
+ }
+ }
+ }
+ }
+
+ (MethodId::__Result as i32).write_unitmap("[METHOD]", &mut __map);
+ let mut __parcel = Parcel::new();
+ __parcel.set_seq_num(seq_num);
+ __map.serialize(&mut __parcel);
+ if let Err(ret) = __parcel.try_send(port) {
+ error!("Failed to send parcel {}", ret);
+ }
+ </SYNC?>
+ <ASYNC?>
+ if self.check_privileges(MethodId::<METHOD_ID> as i32) {
+ error!("Permission denied");
+ return;
+ }
+
+ <RECEIVER_BODY*>
+ let mut <ID>: <TYPE> = Default::default();
+ unit_map.read("<ID>", &mut <ID>);
+ </RECEIVER_BODY*>
+ <DELEGATER_RECEIVER_BODY*>
+ let mut <ID> = <TYPE>::new(callback_port);
+ unit_map.read("<ID>", &mut <ID>);
+ </DELEGATER_RECEIVER_BODY*>
+ if let Err(err) = &self.handler.<FN_NAME>(<IDS>) {
+ error!("Error: cause({}), message({}", err.cause, err.message);
+ }
+ </ASYNC?>
+ }
+ </METHODS*>
+ }
+
+ pub struct <IFACE_NAME><'a> {
+ stub: Arc<Mutex<Stub<'a>>>,
+ services: Vec<Box<Service>>,
+ }
+
+ impl<'b> <IFACE_NAME><'b> {
+
+ /// <summary>
+ /// Constructor for this struct
+ /// </summary>
+ pub fn new<T: ServiceHandler>() -> Arc<Mutex<<IFACE_NAME><'b>>> {
+ info!("stub new");
+ let s = Arc::new(Mutex::new(Stub::try_new("<IFACE_NAME>").unwrap()));
+ let ret = Arc::new(Mutex::new(Self {
+ stub: s.clone(),
+ services: vec![],
+ }));
+
+ let mut clone_ret = ret.clone();
+ s.lock().unwrap().on_connected(move |sender, instance| {
+ let mut service = Box::new(Service::new(sender, instance, &T::new));
+ let mut port = clone_ret.lock().unwrap().get_port(&PortType::Callback, instance);
+ service.set_port(port);
+ service.on_create();
+ clone_ret.lock().unwrap().services.push(service);
+ });
+
+ let mut clone_ret = ret.clone();
+ s.lock().unwrap().on_disconnected(move |sender, instance| {
+ let mut services = &mut clone_ret.lock().unwrap().services;
+ services.retain_mut(|svc| {
+ if svc.get_instance() == instance {
+ svc.on_terminate();
+ return true;
+ }
+
+ false
+ });
+ });
+
+ let mut clone_ret = ret.clone();
+ s.lock().unwrap().on_received(move |sender, instance, port| -> i32 {
+ let callback_port = Arc::new(clone_ret.lock().unwrap().get_port(&PortType::Callback, instance));
+ let mut services = &mut clone_ret.lock().unwrap().services;
+ for mut svc in services {
+ if svc.get_instance() == instance {
+ let mut parcel = Parcel::from(port);
+ svc.dispatch(port, callback_port, &mut parcel);
+ return 0;
+ }
+ }
+
+ error!("Failed to find <IFACE_NAME> context. instance({})", instance);
+ -1
+ });
+
+ <INTERFACE_PRIVILEGES*>
+ s.lock().unwrap().add_privilege("<INTERFACE_PRIVILEGE>");
+ </INTERFACE_PRIVILEGES*>
+ <SET_TRUSTED?>
+ s.lock().unwrap().set_trusted(true);
+ </SET_TRUSTED?>
+ ret
+ }
+
+ <EXTENSION_BLOCK?>
+ pub fn has_pending_request(&self) -> Result<bool, ErrorId> {
+ match self.stub.lock().unwrap().has_pending_request() {
+ Ok(has_request) => { Ok(has_request) }
+ Err(id) => Err(convert_err(id))
+ }
+ }
+ </EXTENSION_BLOCK?>
+
+ /// <summary>
+ /// Gets the port
+ /// </summary>
+ /// <param name="port_type">The port type</param>
+ /// <param name="instance">The instance id of the connection</param>
+ pub fn get_port(&self, port_type: &PortType, instance: &str) -> Port {
+ self.stub.lock().unwrap().get_port(port_type, instance)
+ }
+
+ /// <summary>
+ /// Listens to client apps
+ /// </summary>
+ /// <exception cref="IoError">
+ /// Returns when internal I/O error happen.
+ /// </exception>
+ pub fn listen(&mut self) -> Result<(), ErrorId> {
+ if let Err(error) = self.stub.lock().unwrap().try_listen() {
+ error!("listen error: {:?}", error);
+ return Err(convert_err(error));
+ }
+
+ Ok(())
+ }
+ }
+ </INTERFACE_BLOCK!>
+}
+</MODULES*>
+</MODULE_BLOCK!>
+)__rs_cb";
+
+#endif // IDLC_RS_GEN_RS_STUB_GEN_CB_H_
tidl::Parser ps(options->IsBetaEnabled(), options->IsCion(),
options->IsMqtt(),
- options->GetType() == tidl::Options::Type::TYPE_GROUP ? true : false);
+ options->GetType() == tidl::Options::Type::TYPE_GROUP ? true : false,
+ options->GetLanguage() == tidl::Options::LanguageType::LANGUAGE_TYPE_RUST);
std::string path(options->GetInput());
if (!ps.ParseFromFile(path))
-h, --help Show help options
Additional Options:
- -l, --language=LANGUAGE Select generating language (C, C++, C#, Java(CION & MQTT only), Dart).
+ -l, --language=LANGUAGE Select generating language (C, C++, C#, Java(CION & MQTT only), Dart, Rust).
-i, --input=INPUT A tidl interface file.
-o, --output=OUTPUT The generated interface file.
-n, --namespace Add the prefix in the funtion name as output file name (C language only).
return Options::LANGUAGE_TYPE_C;
else if (str_type == "dart")
return Options::LANGUAGE_TYPE_DART;
+ else if (str_type == "rust")
+ return Options::LANGUAGE_TYPE_RUST;
return Options::LANGUAGE_TYPE_UNKNOWN;
}
LANGUAGE_TYPE_CPP,
LANGUAGE_TYPE_CSHARP,
LANGUAGE_TYPE_JAVA,
- LANGUAGE_TYPE_DART
+ LANGUAGE_TYPE_DART,
+ LANGUAGE_TYPE_RUST,
};
Options();
#include "idlc/gen/version2/cs_group_generator.h"
#include "idlc/gen/version2/cs_proxy_generator.h"
#include "idlc/gen/version2/cs_stub_generator.h"
+#include "idlc/gen/version2/rs_group_gen.h"
+#include "idlc/gen/version2/rs_proxy_gen.h"
+#include "idlc/gen/version2/rs_stub_gen.h"
#include "idlc/options.h"
namespace tidl {
{std::make_pair(Options::Type::TYPE_STUB, Options::LANGUAGE_TYPE_CSHARP),
std::bind(&DefaultGenerator::GenCsharpStubCode, this,
std::placeholders::_1, std::placeholders::_2)},
+ {std::make_pair(Options::Type::TYPE_STUB, Options::LANGUAGE_TYPE_RUST),
+ std::bind(&DefaultGenerator::GenRustStubCode, this,
+ std::placeholders::_1, std::placeholders::_2)},
// Proxy
{std::make_pair(Options::Type::TYPE_PROXY, Options::LANGUAGE_TYPE_C),
{std::make_pair(Options::Type::TYPE_PROXY, Options::LANGUAGE_TYPE_CSHARP),
std::bind(&DefaultGenerator::GenCsharpProxyCode, this,
std::placeholders::_1, std::placeholders::_2)},
+ {std::make_pair(Options::Type::TYPE_PROXY, Options::LANGUAGE_TYPE_RUST),
+ std::bind(&DefaultGenerator::GenRustProxyCode, this,
+ std::placeholders::_1, std::placeholders::_2)},
// Group
{std::make_pair(Options::Type::TYPE_GROUP, Options::LANGUAGE_TYPE_C),
{std::make_pair(Options::Type::TYPE_GROUP, Options::LANGUAGE_TYPE_CSHARP),
std::bind(&DefaultGenerator::GenCsharpGroupCode, this,
std::placeholders::_1, std::placeholders::_2)},
+ {std::make_pair(Options::Type::TYPE_GROUP, Options::LANGUAGE_TYPE_RUST),
+ std::bind(&DefaultGenerator::GenRustGroupCode, this,
+ std::placeholders::_1, std::placeholders::_2)},
};
}
stub.Run(options->GetOutput() + ".cs");
}
+void DefaultGenerator::GenRustStubCode(std::shared_ptr<Options> options,
+ const Parser& ps) {
+ tidl::version2::RsStubGen stub(ps.GetDoc(), options);
+ stub.EnableProxy(false);
+ stub.SetChannelType(static_cast<Generator::ChannelType>(options->GetType()));
+ stub.Run(options->GetOutput(), true);
+}
+
void DefaultGenerator::GenCProxyCode(std::shared_ptr<Options> options,
const Parser& ps) {
CProxyHeaderGenerator proxy_header(ps.GetDoc());
proxy.Run(options->GetOutput() + ".cs");
}
+void DefaultGenerator::GenRustProxyCode(std::shared_ptr<Options> options,
+ const Parser &ps) {
+ RsProxyGen proxy(ps.GetDoc());
+ proxy.EnableProxy(true);
+ proxy.SetChannelType(static_cast<Generator::ChannelType>(options->GetType()));
+ proxy.Run(options->GetOutput(), true);
+}
+
void DefaultGenerator::GenCGroupCode(std::shared_ptr<Options> options,
const Parser& ps) {
CGroupHeaderGenerator group_header(ps.GetDoc());
group.Run(options->GetOutput() + ".cs");
}
+void DefaultGenerator::GenRustGroupCode(std::shared_ptr<Options> options,
+ const Parser &ps) {
+ RsGroupGen group(ps.GetDoc());
+ group.SetChannelType(static_cast<Generator::ChannelType>(options->GetType()));
+ group.Run(options->GetOutput(), true);
+}
+
} // namespace version2
} // namespace tidl
void GenCStubCode(std::shared_ptr<Options> options, const Parser& ps);
void GenCppStubCode(std::shared_ptr<Options> options, const Parser& ps);
void GenCsharpStubCode(std::shared_ptr<Options> options, const Parser& ps);
+ void GenRustStubCode(std::shared_ptr<Options> options, const Parser& ps);
/// Proxy
void GenCProxyCode(std::shared_ptr<Options> options, const Parser& ps);
void GenCppProxyCode(std::shared_ptr<Options> options, const Parser& ps);
void GenCsharpProxyCode(std::shared_ptr<Options> options, const Parser& ps);
+ void GenRustProxyCode(std::shared_ptr<Options> options, const Parser& ps);
/// Group
void GenCGroupCode(std::shared_ptr<Options> options, const Parser& ps);
void GenCppGroupCode(std::shared_ptr<Options> options, const Parser& ps);
void GenCsharpGroupCode(std::shared_ptr<Options> options, const Parser& ps);
+ void GenRustGroupCode(std::shared_ptr<Options> options, const Parser& ps);
private:
std::unordered_map<GeneratorCond, GeneratorFunc, PairHash> funcs_;