SignalBase::SignalBase(const qi::Signature& sig, OnSubscribers onSubscribers) : _p(new SignalBasePrivate) { //Dynamic mean AnyArguments here. if (sig.type() != qi::Signature::Type_Dynamic && sig.type() != qi::Signature::Type_Tuple) throw std::runtime_error("Signal signature should be tuple, or AnyArguments"); _p->onSubscribers = onSubscribers; _p->signature = sig; }
//convert args then call setValues void Message::setValues(const std::vector<qi::AnyReference>& in, const qi::Signature& expectedSignature, ObjectHost* context, StreamContext* streamContext) { qi::Signature argsSig = qi::makeTupleSignature(in, false); if (expectedSignature == argsSig) { setValues(in, context, streamContext); return; } if (expectedSignature == "m") { /* We need to send a dynamic containing the value tuple to push the * signature. This wraps correctly without copying the data. */ std::vector<qi::TypeInterface*> types; std::vector<void*> values; types.resize(in.size()); values.resize(in.size()); for (unsigned i=0; i<in.size(); ++i) { types[i] = in[i].type(); values[i] = in[i].rawValue(); } AnyReference tuple = makeGenericTuplePtr(types, values); AnyValue val(tuple, false, false); encodeBinary(&_p->buffer, AnyReference::from(val), boost::bind(serializeObject, _1, context), streamContext); return; } /* This check does not makes sense for this transport layer who does not care, * But it checks a general rule that is true for all the messages we use and * it can help catch many mistakes. */ if (expectedSignature.type() != Signature::Type_Tuple) throw std::runtime_error("Expected a tuple, got " + expectedSignature.toString()); AnyReferenceVector nargs(in); SignatureVector src = argsSig.children(); SignatureVector dst = expectedSignature.children(); if (src.size() != dst.size()) throw std::runtime_error("remote call: signature size mismatch"); SignatureVector::iterator its = src.begin(), itd = dst.begin(); boost::dynamic_bitset<> allocated(nargs.size()); for (unsigned i = 0; i< nargs.size(); ++i, ++its, ++itd) { if (*its != *itd) { ::qi::TypeInterface* target = ::qi::TypeInterface::fromSignature(*itd); if (!target) throw std::runtime_error("remote call: Failed to obtain a type from signature " + (*itd).toString()); std::pair<AnyReference, bool> c = nargs[i].convert(target); if (!c.first.type()) { throw std::runtime_error( _QI_LOG_FORMAT("remote call: failed to convert argument %s from %s to %s", i, (*its).toString(), (*itd).toString())); } nargs[i] = c.first; allocated[i] = c.second; } } setValues(nargs, context, streamContext); for (unsigned i = 0; i< nargs.size(); ++i) if (allocated[i]) nargs[i].destroy(); }
void SignatureConvertor::visit(const qi::Signature& sig) { switch(sig.type()) { case '[': visitList(sig); break; case '{': visitMap(sig); break; case '(': visitTuple(sig); break; case '#': visitVarArgs(sig); break; default: visitSimple(sig); break; } }