Vuo  2.3.2
VuoCompilerPublishedPort.cc
Go to the documentation of this file.
1 
10 #include <dlfcn.h>
11 #include <sstream>
16 #include "VuoCompilerType.hh"
17 #include "VuoCable.hh"
18 #include "VuoGenericType.hh"
19 #include "VuoPort.hh"
20 #include "VuoStringUtilities.hh"
21 #include "VuoHeap.h"
22 
27 {
29  VuoCompilerPublishedPortClass *portClass = new VuoCompilerPublishedPortClass(name, eventOrData);
30  portClass->setDataVuoType(type);
31  return static_cast<VuoCompilerPublishedPort *>( portClass->newPort() );
32 }
33 
38  : VuoCompilerPort(basePort)
39 {
40 }
41 
46 {
47  return getBase()->getClass()->getName();
48 }
49 
56 void VuoCompilerPublishedPort::setInitialValue(string initialValueAsString)
57 {
58  static_cast<VuoCompilerPublishedPortClass *>(getBase()->getClass()->getCompiler())->setDetail("default", initialValueAsString);
59 }
60 
65 {
67  json_object *value = NULL;
68  if (json_object_object_get_ex(details, "default", &value))
69  return json_object_to_json_string_ext(value, JSON_C_TO_STRING_PLAIN);
70 
71  return "";
72 }
73 
81 {
82  // Coalesce the details across all connected ports.
83  json_object *coalescedDetails = json_object_new_object();
84 
85  VuoType *type = static_cast<VuoCompilerPortClass *>(getBase()->getClass()->getCompiler())->getDataVuoType();
86  if (isInput && type)
87  {
88 // VLog("Coalescing input %s %s:", type->getModuleKey().c_str(), getIdentifier().c_str());
89  json_object *coalescedSuggestedMin = NULL;
90  json_object *coalescedSuggestedMax = NULL;
91  json_object *coalescedSuggestedStep = NULL;
92  json_object *coalescedAuto = NULL;
93  json_object *coalescedAutoSupersedesDefault = NULL;
94  json_object *coalescedMenuItems = NULL;
95  bool atLeastOneDataSourceCoalesced = false;
96 
97  vector<VuoCable *> connectedCables = getBase()->getConnectedCables();
98  for (vector<VuoCable *>::iterator i = connectedCables.begin(); i != connectedCables.end(); ++i)
99  {
100  VuoPort *connectedPort = (*i)->getToPort();
101  if (! (connectedPort && connectedPort->hasCompiler()) )
102  continue;
103 
104  VuoCompilerInputEventPortClass *connectedInputEventPortClass = dynamic_cast<VuoCompilerInputEventPortClass *>(connectedPort->getClass()->getCompiler());
105  if (connectedInputEventPortClass)
106  {
107  VuoCompilerInputDataClass *connectedInputDataClass = connectedInputEventPortClass->getDataClass();
108  if (connectedInputDataClass)
109  {
110  json_object *js = connectedInputDataClass->getDetails();
111  json_object *o;
112 
113  string typeName = type->getModuleKey();
114 
115  if (json_object_object_get_ex(js, "suggestedMin", &o))
116  {
117 // VLog(" Cable with suggestedMin %s", json_object_to_json_string(o));
118  if (!coalescedSuggestedMin)
119  coalescedSuggestedMin = o;
120  else
121  {
122  // Use the larger of the current port's suggestedMin.x and all previous ports' suggestedMin.x.
124  bool newIsBetter = false;
125  if (typeName == "VuoInteger")
126  newIsBetter = json_object_get_int64(o) > json_object_get_int64(coalescedSuggestedMin);
127  else if (typeName == "VuoReal")
128  newIsBetter = json_object_get_double(o) > json_object_get_double(coalescedSuggestedMin);
129  else if (typeName == "VuoPoint2d" || typeName == "VuoPoint3d" || typeName == "VuoPoint4d")
130  {
131  double oldX=0,newX=0;
132  json_object *x;
133  if (json_object_object_get_ex(coalescedSuggestedMin, "x", &x))
134  oldX = json_object_get_double(x);
135  if (json_object_object_get_ex(o, "x", &x))
136  newX = json_object_get_double(x);
137  newIsBetter = newX > oldX;
138  }
139 
140  if (newIsBetter)
141  coalescedSuggestedMin = o;
142  }
143  }
144 
145  if (json_object_object_get_ex(js, "suggestedMax", &o))
146  {
147 // VLog(" Cable with suggestedMax %s", json_object_to_json_string(o));
148  if (!coalescedSuggestedMax)
149  coalescedSuggestedMax = o;
150  else
151  {
152  // Use the smaller of the current port's suggestedMax.x and all previous ports' suggestedMax.x.
154  bool newIsBetter = false;
155  if (typeName == "VuoInteger")
156  newIsBetter = json_object_get_int64(o) < json_object_get_int64(coalescedSuggestedMax);
157  else if (typeName == "VuoReal")
158  newIsBetter = json_object_get_double(o) < json_object_get_double(coalescedSuggestedMax);
159  else if (typeName == "VuoPoint2d" || typeName == "VuoPoint3d" || typeName == "VuoPoint4d")
160  {
161  double oldX=0,newX=0;
162  json_object *x;
163  if (json_object_object_get_ex(coalescedSuggestedMax, "x", &x))
164  oldX = json_object_get_double(x);
165  if (json_object_object_get_ex(o, "x", &x))
166  newX = json_object_get_double(x);
167  newIsBetter = newX < oldX;
168  }
169 
170  if (newIsBetter)
171  coalescedSuggestedMax = o;
172  }
173  }
174 
175  if (json_object_object_get_ex(js, "suggestedStep", &o))
176  {
177 // VLog(" Cable with suggestedStep %s", json_object_to_json_string(o));
178  if (!coalescedSuggestedStep)
179  coalescedSuggestedStep = o;
180  else
181  {
182  // Use the smaller of the current port's suggestedStep.x and all previous ports' suggestedStep.x.
184  bool newIsBetter = false;
185  if (typeName == "VuoInteger")
186  newIsBetter = json_object_get_int64(o) < json_object_get_int64(coalescedSuggestedStep);
187  else if (typeName == "VuoReal")
188  newIsBetter = json_object_get_double(o) < json_object_get_double(coalescedSuggestedStep);
189  else if (typeName == "VuoPoint2d" || typeName == "VuoPoint3d" || typeName == "VuoPoint4d")
190  {
191  double oldX=0,newX=0;
192  json_object *x;
193  if (json_object_object_get_ex(coalescedSuggestedStep, "x", &x))
194  oldX = json_object_get_double(x);
195  if (json_object_object_get_ex(o, "x", &x))
196  newX = json_object_get_double(x);
197  newIsBetter = newX < oldX;
198  }
199 
200  if (newIsBetter)
201  coalescedSuggestedStep = o;
202  }
203  }
204 
205  if (json_object_object_get_ex(js, "auto", &o))
206  {
207 // VLog(" Cable with auto %s", json_object_to_json_string(o));
208  if (!atLeastOneDataSourceCoalesced)
209  {
210  coalescedAuto = o;
211 
212  if (json_object_object_get_ex(js, "autoSupersedesDefault", &o))
213  coalescedAutoSupersedesDefault = o;
214  }
215  else if (coalescedAuto != o)
216  {
217  coalescedAuto = NULL;
218  coalescedAutoSupersedesDefault = NULL;
219  }
220  }
221  else
222  {
223  coalescedAuto = NULL;
224  coalescedAutoSupersedesDefault = NULL;
225  }
226 
227  if (json_object_object_get_ex(js, "menuItems", &o))
228  {
229 // VLog(" Cable with menuItems %s", json_object_to_json_string(o));
230  if (!coalescedMenuItems)
231  coalescedMenuItems = o;
232  }
233 
234  atLeastOneDataSourceCoalesced = true;
235  } // end if (connectedInputDataClass)
236  }
237  }
238 
239  if (coalescedSuggestedMin)
240  json_object_object_add(coalescedDetails, "suggestedMin", coalescedSuggestedMin);
241  if (coalescedSuggestedMax)
242  json_object_object_add(coalescedDetails, "suggestedMax", coalescedSuggestedMax);
243  if (coalescedSuggestedStep)
244  json_object_object_add(coalescedDetails, "suggestedStep", coalescedSuggestedStep);
245 
246  // Use the coalesced auto value only if it came from a single internal source and there
247  // are no connected data sources without auto values.
248  if (coalescedAuto)
249  json_object_object_add(coalescedDetails, "auto", coalescedAuto);
250  if (coalescedAutoSupersedesDefault)
251  json_object_object_add(coalescedDetails, "autoSupersedesDefault", coalescedAutoSupersedesDefault);
252 
253  if (!coalescedMenuItems)
254  {
255  // If it's a hard-enum type, maybe we can get the menu items from the currently-loaded type.
256  // Copied from VuoRuntimeCommunicator::mergeEnumDetails.
257 
258  string allowedValuesFunctionName = type->getModuleKey() + "_getAllowedValues";
259  typedef void *(*allowedValuesFunctionType)(void);
260  allowedValuesFunctionType allowedValuesFunction = (allowedValuesFunctionType)dlsym(RTLD_SELF, allowedValuesFunctionName.c_str());
261 
262  string getJsonFunctionName = type->getModuleKey() + "_getJson";
263  typedef json_object *(*getJsonFunctionType)(int64_t);
264  getJsonFunctionType getJsonFunction = (getJsonFunctionType)dlsym(RTLD_SELF, getJsonFunctionName.c_str());
265 
266  string summaryFunctionName = type->getModuleKey() + "_getSummary";
267  typedef char *(*summaryFunctionType)(int64_t);
268  summaryFunctionType summaryFunction = (summaryFunctionType)dlsym(RTLD_SELF, summaryFunctionName.c_str());
269 
270  string listCountFunctionName = "VuoListGetCount_" + type->getModuleKey();
271  typedef unsigned long (*listCountFunctionType)(void *);
272  listCountFunctionType listCountFunction = (listCountFunctionType)dlsym(RTLD_SELF, listCountFunctionName.c_str());
273 
274  string listValueFunctionName = "VuoListGetValue_" + type->getModuleKey();
275  typedef int64_t (*listValueFunctionType)(void *, unsigned long);
276  listValueFunctionType listValueFunction = (listValueFunctionType)dlsym(RTLD_SELF, listValueFunctionName.c_str());
277 
278  if (allowedValuesFunction && getJsonFunction && summaryFunction && listCountFunction && listValueFunction)
279  {
280  void *allowedValues = allowedValuesFunction();
281  VuoRetain(allowedValues);
282  unsigned long listCount = listCountFunction(allowedValues);
283  json_object *menuItems = json_object_new_array();
284  for (unsigned long i = 1; i <= listCount; ++i)
285  {
286  int64_t value = listValueFunction(allowedValues, i);
287  json_object *js = getJsonFunction(value);
288  if (!json_object_is_type(js, json_type_string))
289  continue;
290  const char *key = json_object_get_string(js);
291  char *summary = summaryFunction(value);
292 
293  json_object *menuItem = json_object_new_object();
294  json_object_object_add(menuItem, "value", json_object_new_string(key));
295  json_object_object_add(menuItem, "name", json_object_new_string(summary));
296  json_object_array_add(menuItems, menuItem);
297 
298  free(summary);
299  }
300  VuoRelease(allowedValues);
301 
302  if (json_object_array_length(menuItems))
303  coalescedMenuItems = menuItems;
304  }
305  }
306  if (coalescedMenuItems)
307  json_object_object_add(coalescedDetails, "menuItems", coalescedMenuItems);
308 
309  json_object_get(coalescedSuggestedMin);
310  json_object_get(coalescedSuggestedMax);
311  json_object_get(coalescedSuggestedStep);
312  json_object_get(coalescedAuto);
313  json_object_get(coalescedAutoSupersedesDefault);
314  json_object_get(coalescedMenuItems);
315 
316 // VLog(" Result: %s", json_object_to_json_string(coalescedDetails));
317  }
318 
319 
320  // Override the coalesced details for any details explicitly set for this published port.
321 
322  json_object *details = static_cast<VuoCompilerPublishedPortClass *>(getBase()->getClass()->getCompiler())->getDetails();
323  json_object_object_foreach(details, key, val)
324  {
325  json_object_object_add(coalescedDetails, key, val);
326  json_object_get(val);
327  }
328 
329 
330  return coalescedDetails;
331 }
332 
338 {
339  ostringstream output;
340 
341  string attributePrefix = " _" + getBase()->getClass()->getName();
342 
343  VuoType *type = getDataVuoType();
344  string typeName = type ? type->getModuleKey() : "event";
345  string escapedTypeName = VuoStringUtilities::transcodeToGraphvizIdentifier(typeName);
346 
347  // @todo: The following check may be removed once it is impossible for a published port
348  // to have a generic type (https://b33p.net/kosada/node/7673, https://b33p.net/kosada/node/7674,
349  // https://b33p.net/kosada/node/7698). For now, make sure not to associate generic types
350  // with published ports in the Graphviz source, so that the upgrade manager
351  // (https://b33p.net/kosada/node/7698) can reliably detect published ports whose types need to be
352  // inferred and correct for the situation in which the inferred type is generic.
353  if (! VuoGenericType::isGenericTypeName(typeName))
354  output << attributePrefix << "_type=\"" << escapedTypeName << "\"";
355 
356  json_object *details = getDetails(true);
357  json_object_object_foreach(details, key, val)
358  {
359  string attributeSuffix;
360  if (strcmp(key, "default") == 0)
361  {
362  if (! val)
363  continue;
364 
365  attributeSuffix = "";
366  }
367  else
368  attributeSuffix = string("_") + key;
369 
370  string attributeValue = json_object_to_json_string_ext(val, JSON_C_TO_STRING_PLAIN);
371  string escapedAttributeValue = VuoStringUtilities::transcodeToGraphvizIdentifier(attributeValue);
372 
373  output << attributePrefix << attributeSuffix << "=\"" << escapedAttributeValue << "\"";
374  }
375 
376  return output.str();
377 }
378 
382 Value * VuoCompilerPublishedPort::generateCreatePortContext(Module *module, BasicBlock *block)
383 {
384  return NULL;
385 }