DCCL v5
Loading...
Searching...
No Matches
dynamic_conditions.cpp
1// Copyright 2022-2023:
2// GobySoft, LLC (2013-)
3// Community contributors (see AUTHORS file)
4// File authors:
5// Toby Schneider <toby@gobysoft.org>
6//
7//
8// This file is part of the Dynamic Compact Control Language Library
9// ("DCCL").
10//
11// DCCL is free software: you can redistribute it and/or modify
12// it under the terms of the GNU Lesser General Public License as published by
13// the Free Software Foundation, either version 2.1 of the License, or
14// (at your option) any later version.
15//
16// DCCL is distributed in the hope that it will be useful,
17// but WITHOUT ANY WARRANTY; without even the implied warranty of
18// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19// GNU Lesser General Public License for more details.
20//
21// You should have received a copy of the GNU Lesser General Public License
22// along with DCCL. If not, see <http://www.gnu.org/licenses/>.
23#include "dynamic_conditions.h"
24#include "exception.h"
25
26#if DCCL_HAS_LUA
27#include "thirdparty/sol/sol.hpp"
28// symbol in lua-protobuf/pb.c so we can load this using sol's require call
29LUALIB_API int luaopen_pb(lua_State* L);
30#define SOL_ALL_SAFETIES_ON 1
31#define SOL_PRINT_ERRORS 1
32#endif
33
34void build_file_desc_set(const google::protobuf::FileDescriptor* file_desc,
35 google::protobuf::FileDescriptorSet& file_desc_set)
36{
37 for (int i = 0, n = file_desc->dependency_count(); i < n; ++i)
38 build_file_desc_set(file_desc->dependency(i), file_desc_set);
39
40 google::protobuf::FileDescriptorProto* file_desc_proto = file_desc_set.add_file();
41 file_desc->CopyTo(file_desc_proto);
42}
43
44dccl::DynamicConditions::DynamicConditions() = default;
45
46dccl::DynamicConditions::~DynamicConditions()
47{
48#if DCCL_HAS_LUA
49 if (lua_)
50 {
51 // without this, we get a segfault in Ubuntu jammy
52 lua_->script("pb.clear()");
53 delete lua_;
54 }
55#endif
56}
57
58void dccl::DynamicConditions::regenerate(const google::protobuf::Message* this_msg,
59 const google::protobuf::Message* root_msg, int index)
60{
61 if (index >= 0)
62 set_repeated_index(index);
63
64 this_msg_ = this_msg;
65 root_msg_ = root_msg;
66 if (!this_msg_)
67 this_msg_ = root_msg_;
68
69#if DCCL_HAS_LUA
70 if (this_msg_ && root_msg_)
71 {
72 if (!lua_)
73 {
74 lua_ = new sol::state;
75 lua_->open_libraries();
76 lua_->require("pb", luaopen_pb);
77 }
78
79 sol::load_result desc_load = lua_->load(R"(local desc = ...; return pb.load(desc) )");
80
81 google::protobuf::FileDescriptorSet file_desc_set;
82 build_file_desc_set(root_msg_->GetDescriptor()->file(), file_desc_set);
83
84 auto [desc_load_success, desc_load_value] =
85 std::tuple<bool, int>(desc_load(file_desc_set.SerializeAsString()));
86 assert(desc_load_success);
87 const auto& decode_script = R"(
88 local this_encoded_msg, this_type, root_encoded_msg, root_type, cpp_index = ...;
89 pb.option('use_default_metatable');
90 root = pb.decode(root_type, root_encoded_msg);
91 this = pb.decode(this_type, this_encoded_msg); this_index = cpp_index+1;
92 return this;
93 )";
94
95 sol::load_result decode_message = lua_->load(decode_script);
96 if (!decode_message.valid())
97 {
98 sol::error err = decode_message;
99 throw(Exception(std::string("Failed to load condition script into the Lua program: ") +
100 err.what(),
101 this_msg_->GetDescriptor()));
102 }
103
104 auto index = index_;
105
106 sol::table decoded_message = decode_message(
107 this_msg_->SerializePartialAsString(), this_msg_->GetDescriptor()->full_name(),
108 root_msg_->SerializePartialAsString(), root_msg_->GetDescriptor()->full_name(), index);
109 }
110#endif
111}
112
113const dccl::DCCLFieldOptions::Conditions& dccl::DynamicConditions::conditions()
114{
115 if (field_desc_)
116 return field_desc_->options().GetExtension(dccl::field).dynamic_conditions();
117 else
118 throw(Exception("Null field_desc"));
119}
120
121bool dccl::DynamicConditions::has_max_bytes()
122{
123 return msg_desc_ &&
124 msg_desc_->options().GetExtension(dccl::msg).has_dynamic_conditions() &&
125 msg_desc_->options().GetExtension(dccl::msg).dynamic_conditions().has_max_bytes();
126}
127
128bool dccl::DynamicConditions::required()
129{
130#if DCCL_HAS_LUA
131 if (is_initialized())
132 {
133 if (conditions().has_required_if())
134 {
135 auto condition_script = return_prefix(conditions().required_if());
136 bool required = lua_->script(condition_script);
137 return required;
138 }
139 else if (conditions().has_only_if())
140 {
141 auto condition_script = return_prefix(conditions().only_if());
142 bool only = lua_->script(condition_script);
143 return only;
144 }
145 else
146 {
147 return false;
148 }
149 }
150 else
151 {
152 return false;
153 }
154
155#else
156 throw(Exception("DCCL built without Lua support: cannot use dynamic_conditions"));
157#endif
158}
159
160bool dccl::DynamicConditions::omit()
161{
162#if DCCL_HAS_LUA
163 if (is_initialized())
164 {
165 if (conditions().has_omit_if())
166 {
167 auto condition_script = return_prefix(conditions().omit_if());
168 bool omit = lua_->script(condition_script);
169 return omit;
170 }
171 else if (conditions().has_only_if())
172 {
173 auto condition_script = return_prefix(conditions().only_if());
174 bool only = lua_->script(condition_script);
175 return !only;
176 }
177 else
178 {
179 return false;
180 }
181 }
182 else
183 {
184 return false;
185 }
186#else
187 throw(Exception("DCCL built without Lua support: cannot use dynamic_conditions"));
188#endif
189}
190
191double dccl::DynamicConditions::min()
192{
193#if DCCL_HAS_LUA
194 if (is_initialized())
195 {
196 auto condition_script = return_prefix(conditions().min());
197 double v = lua_->script(condition_script);
198 return v;
199 }
200 else
201 {
202 return -std::numeric_limits<double>::infinity();
203 }
204#else
205 throw(Exception("DCCL built without Lua support: cannot use dynamic_conditions"));
206#endif
207}
208
209double dccl::DynamicConditions::max()
210{
211#if DCCL_HAS_LUA
212 if (is_initialized())
213 {
214 auto condition_script = return_prefix(conditions().max());
215 double v = lua_->script(condition_script);
216 return v;
217 }
218 else
219 {
220 return std::numeric_limits<double>::infinity();
221 }
222#else
223 throw(Exception("DCCL built without Lua support: cannot use dynamic_conditions"));
224#endif
225}
226
227uint32_t dccl::DynamicConditions::max_bytes()
228{
229#if DCCL_HAS_LUA
230 if (is_message_initialized())
231 {
232 auto condition_script = return_prefix(
233 msg_desc_->options().GetExtension(dccl::msg).dynamic_conditions().max_bytes());
234 double v = lua_->script(condition_script);
235 return static_cast<uint32_t>(v);
236 }
237 else
238 {
239 return std::numeric_limits<uint32_t>::max();
240 }
241#else
242 throw(Exception("DCCL built without Lua support: cannot use dynamic_conditions"));
243#endif
244}