| 479 | |
| 480 | template <typename T> |
| 481 | inline Expected<Timestamp> TreeNode::getInputStamped(const std::string& key, |
| 482 | T& destination) const |
| 483 | { |
| 484 | std::string port_value_str; |
| 485 | |
| 486 | auto input_port_it = config().input_ports.find(key); |
| 487 | if(input_port_it != config().input_ports.end()) |
| 488 | { |
| 489 | port_value_str = input_port_it->second; |
| 490 | } |
| 491 | else if(!config().manifest) |
| 492 | { |
| 493 | return nonstd::make_unexpected(StrCat("getInput() of node '", fullPath(), |
| 494 | "' failed because the manifest is " |
| 495 | "nullptr (WTF?) and the key: [", |
| 496 | key, "] is missing")); |
| 497 | } |
| 498 | else |
| 499 | { |
| 500 | // maybe it is declared with a default value in the manifest |
| 501 | auto port_manifest_it = config().manifest->ports.find(key); |
| 502 | if(port_manifest_it == config().manifest->ports.end()) |
| 503 | { |
| 504 | return nonstd::make_unexpected(StrCat("getInput() of node '", fullPath(), |
| 505 | "' failed because the manifest doesn't " |
| 506 | "contain the key: [", |
| 507 | key, "]")); |
| 508 | } |
| 509 | const auto& port_info = port_manifest_it->second; |
| 510 | // there is a default value |
| 511 | if(port_info.defaultValue().empty()) |
| 512 | { |
| 513 | return nonstd::make_unexpected(StrCat("getInput() of node '", fullPath(), |
| 514 | "' failed because nor the manifest or the " |
| 515 | "XML contain the key: [", |
| 516 | key, "]")); |
| 517 | } |
| 518 | if(port_info.defaultValue().isString()) |
| 519 | { |
| 520 | port_value_str = port_info.defaultValue().cast<std::string>(); |
| 521 | } |
| 522 | else |
| 523 | { |
| 524 | destination = port_info.defaultValue().cast<T>(); |
| 525 | return Timestamp{}; |
| 526 | } |
| 527 | } |
| 528 | |
| 529 | // Helper lambda to parse string using the stored converter if available, |
| 530 | // otherwise fall back to convertFromString<T>. This fixes the plugin issue |
| 531 | // where convertFromString<T> specializations are not visible across shared |
| 532 | // library boundaries (issue #953). |
| 533 | auto parseStringWithConverter = [this, &key](const std::string& str) -> T { |
| 534 | if(config().manifest) |
| 535 | { |
| 536 | auto port_it = config().manifest->ports.find(key); |
| 537 | if(port_it != config().manifest->ports.end()) |
| 538 | { |