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