parseJSON() assign union with scalar value
This commit is contained in:
@@ -43,14 +43,13 @@ int jtree_null(void * ctx)
|
||||
}CATCH()
|
||||
}
|
||||
|
||||
template<typename PVD>
|
||||
void valueAssign(context *self, typename PVD::value_type val)
|
||||
template<typename PVScalarT, typename PVArrayT>
|
||||
void valueAssign(context *self, typename PVScalarT::value_type val)
|
||||
{
|
||||
pvd::Type type(self->stack.back()->getField()->getType());
|
||||
if(type==pvd::scalar) {
|
||||
pvd::PVScalar* fld(static_cast<pvd::PVScalar*>(self->stack.back().get()));
|
||||
if(!fld)
|
||||
throw std::invalid_argument("Not a scalar field");
|
||||
|
||||
fld->putFrom(val);
|
||||
self->stack.pop_back();
|
||||
// structure back at the top of the stack
|
||||
@@ -58,20 +57,61 @@ void valueAssign(context *self, typename PVD::value_type val)
|
||||
} else if(type==pvd::scalarArray) {
|
||||
pvd::PVScalarArray* fld(static_cast<pvd::PVScalarArray*>(self->stack.back().get()));
|
||||
|
||||
PVD* arrfld(dynamic_cast<PVD*>(fld));
|
||||
PVArrayT* arrfld(dynamic_cast<PVArrayT*>(fld));
|
||||
if(!arrfld)
|
||||
throw std::invalid_argument("wrong type for scalar array");
|
||||
|
||||
typename PVD::const_svector carr;
|
||||
typename PVArrayT::const_svector carr;
|
||||
arrfld->swap(carr);
|
||||
|
||||
typename PVD::svector arr(pvd::thaw(carr));
|
||||
typename PVArrayT::svector arr(pvd::thaw(carr));
|
||||
|
||||
arr.push_back(val);
|
||||
|
||||
arrfld->replace(pvd::freeze(arr));
|
||||
|
||||
// leave array field at top of stack
|
||||
|
||||
} else if(type==pvd::union_) {
|
||||
pvd::PVUnion* fld(static_cast<pvd::PVUnion*>(self->stack.back().get()));
|
||||
pvd::UnionConstPtr utype(fld->getUnion());
|
||||
|
||||
if(utype->isVariant()) {
|
||||
typename PVScalarT::shared_pointer elem(pvd::getPVDataCreate()->createPVScalar<PVScalarT>());
|
||||
|
||||
elem->put(val);
|
||||
|
||||
fld->set(elem);
|
||||
|
||||
} else {
|
||||
// attempt automagic assignment
|
||||
|
||||
const pvd::StringArray& names = utype->getFieldNames();
|
||||
const pvd::FieldConstPtrArray types = utype->getFields();
|
||||
assert(names.size()==types.size());
|
||||
|
||||
bool assigned = false;
|
||||
for(size_t i=0, N=names.size(); i<N; i++) {
|
||||
if(types[i]->getType()!=pvd::scalar) continue;
|
||||
|
||||
pvd::PVScalarPtr ufld(fld->select<pvd::PVScalar>(i));
|
||||
try{
|
||||
ufld->putFrom(val);
|
||||
assigned = true;
|
||||
}catch(std::runtime_error&){
|
||||
if(i==N-1)
|
||||
throw;
|
||||
continue;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
if(!assigned)
|
||||
throw std::runtime_error("Unable to select union member");
|
||||
}
|
||||
self->stack.pop_back();
|
||||
// structure back at the top of the stack
|
||||
|
||||
} else {
|
||||
throw std::invalid_argument("Can't assign value");
|
||||
}
|
||||
@@ -80,7 +120,7 @@ void valueAssign(context *self, typename PVD::value_type val)
|
||||
int jtree_boolean(void * ctx, int boolVal)
|
||||
{
|
||||
TRY {
|
||||
valueAssign<pvd::PVBooleanArray>(self, !!boolVal);
|
||||
valueAssign<pvd::PVBoolean, pvd::PVBooleanArray>(self, !!boolVal);
|
||||
return 1;
|
||||
}CATCH()
|
||||
}
|
||||
@@ -88,7 +128,7 @@ int jtree_boolean(void * ctx, int boolVal)
|
||||
int jtree_integer(void * ctx, long integerVal)
|
||||
{
|
||||
TRY {
|
||||
valueAssign<pvd::PVLongArray>(self, integerVal);
|
||||
valueAssign<pvd::PVLong, pvd::PVLongArray>(self, integerVal);
|
||||
return 1;
|
||||
}CATCH()
|
||||
}
|
||||
@@ -96,7 +136,7 @@ int jtree_integer(void * ctx, long integerVal)
|
||||
int jtree_double(void * ctx, double doubleVal)
|
||||
{
|
||||
TRY {
|
||||
valueAssign<pvd::PVDoubleArray>(self, doubleVal);
|
||||
valueAssign<pvd::PVDouble, pvd::PVDoubleArray>(self, doubleVal);
|
||||
return 1;
|
||||
}CATCH()
|
||||
}
|
||||
@@ -106,7 +146,7 @@ int jtree_string(void * ctx, const unsigned char * stringVal,
|
||||
{
|
||||
TRY {
|
||||
std::string val((const char*)stringVal, stringLen);
|
||||
valueAssign<pvd::PVStringArray>(self, val);
|
||||
valueAssign<pvd::PVString, pvd::PVStringArray>(self, val);
|
||||
return 1;
|
||||
}CATCH()
|
||||
}
|
||||
|
||||
@@ -127,6 +127,18 @@ void show_field(args& A, const pvd::PVField* fld)
|
||||
A.strm.put(']');
|
||||
}
|
||||
break;
|
||||
case pvd::union_:
|
||||
{
|
||||
const pvd::PVUnion *U=static_cast<const pvd::PVUnion*>(fld);
|
||||
pvd::PVFieldPtr C(U->get());
|
||||
|
||||
if(!C) {
|
||||
A.strm<<"null";
|
||||
} else {
|
||||
show_field(A, C.get());
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
if(A.opts.ignoreUnprintable)
|
||||
A.strm<<"// unprintable field type";
|
||||
|
||||
@@ -73,7 +73,8 @@ PVStructure::shared_pointer parseJSON(std::istream& strm);
|
||||
*
|
||||
* Restrictions:
|
||||
*
|
||||
* - Union or array of union not permitted
|
||||
* - array of union not permitted
|
||||
* - Only scalar value assigned to union
|
||||
*/
|
||||
epicsShareFunc
|
||||
void parseJSON(std::istream& strm,
|
||||
|
||||
@@ -130,6 +130,11 @@ testFieldEqual(const std::tr1::shared_ptr<epics::pvData::PVStructure>& val, cons
|
||||
return ::detail::testPassx(false)<<" null structure pointer";
|
||||
}
|
||||
typename PVD::shared_pointer fval(val->getSubField<PVD>(name));
|
||||
if(!fval) {
|
||||
epics::pvData::PVUnionPtr uval(val->getSubField<epics::pvData::PVUnion>(name));
|
||||
if(uval)
|
||||
fval = uval->get<PVD>();
|
||||
}
|
||||
if(!fval) {
|
||||
return ::detail::testPassx(false)<<" field '"<<name<<"' with type "<<typeid(PVD).name()<<" does not exist";
|
||||
} else {
|
||||
|
||||
@@ -47,6 +47,38 @@ void testparseanyarray()
|
||||
testFieldEqual<pvd::PVLongArray>(val, "hello", sarr);
|
||||
}
|
||||
|
||||
void testparsebare()
|
||||
{
|
||||
testDiag("testparsebare()");
|
||||
{
|
||||
std::istringstream strm("5");
|
||||
|
||||
pvd::PVIntPtr fld(pvd::getPVDataCreate()->createPVScalar<pvd::PVInt>());
|
||||
|
||||
pvd::parseJSON(strm, fld);
|
||||
|
||||
testOk1(fld->get()==5);
|
||||
}
|
||||
{
|
||||
std::istringstream strm("\"5\"");
|
||||
|
||||
pvd::PVIntPtr fld(pvd::getPVDataCreate()->createPVScalar<pvd::PVInt>());
|
||||
|
||||
pvd::parseJSON(strm, fld);
|
||||
|
||||
testOk1(fld->get()==5);
|
||||
}
|
||||
{
|
||||
std::istringstream strm("\"hello\"");
|
||||
|
||||
pvd::PVStringPtr fld(pvd::getPVDataCreate()->createPVScalar<pvd::PVString>());
|
||||
|
||||
pvd::parseJSON(strm, fld);
|
||||
|
||||
testOk1(fld->get()=="hello");
|
||||
}
|
||||
}
|
||||
|
||||
void testparseanyjunk()
|
||||
{
|
||||
testDiag("testparseanyjunk()");
|
||||
@@ -84,7 +116,9 @@ const char bigtest[] =
|
||||
" {\"a\":5, \"b\":6}\n"
|
||||
" ,{\"a\":7, \"b\":8}\n"
|
||||
" ,{\"a\":9, \"b\":10}\n"
|
||||
" ]\n"
|
||||
" ],\n"
|
||||
" \"any\": \"4.2\",\n"
|
||||
" \"almost\": \"hello\"\n"
|
||||
"}";
|
||||
|
||||
pvd::StructureConstPtr bigtype(pvd::getFieldCreate()->createFieldBuilder()
|
||||
@@ -100,6 +134,11 @@ pvd::StructureConstPtr bigtype(pvd::getFieldCreate()->createFieldBuilder()
|
||||
->add("a", pvd::pvInt)
|
||||
->add("b", pvd::pvInt)
|
||||
->endNested()
|
||||
->add("any", pvd::getFieldCreate()->createVariantUnion())
|
||||
->addNestedUnion("almost")
|
||||
->add("one", pvd::pvInt)
|
||||
->add("two", pvd::pvString)
|
||||
->endNested()
|
||||
->createStructure()
|
||||
);
|
||||
|
||||
@@ -145,6 +184,9 @@ void testInto()
|
||||
testFieldEqual<pvd::PVInt>(elems[2], "a", 9);
|
||||
testFieldEqual<pvd::PVInt>(elems[2], "b", 10);
|
||||
}
|
||||
|
||||
testFieldEqual<pvd::PVString>(val, "any", "4.2");
|
||||
testFieldEqual<pvd::PVString>(val, "almost", "hello");
|
||||
}
|
||||
|
||||
void testroundtrip()
|
||||
@@ -204,7 +246,9 @@ void testroundtrip()
|
||||
"}},"
|
||||
"\"sarr\": [{\"a\": 5,\"b\": 6},"
|
||||
"{\"a\": 7,\"b\": 8},"
|
||||
"{\"a\": 9,\"b\": 10}]"
|
||||
"{\"a\": 9,\"b\": 10}],"
|
||||
"\"any\": \"4.2\","
|
||||
"\"almost\": \"hello\""
|
||||
"}");
|
||||
}
|
||||
|
||||
@@ -212,10 +256,11 @@ void testroundtrip()
|
||||
|
||||
MAIN(testjson)
|
||||
{
|
||||
testPlan(22);
|
||||
testPlan(27);
|
||||
try {
|
||||
testparseany();
|
||||
testparseanyarray();
|
||||
testparsebare();
|
||||
testparseanyjunk();
|
||||
testInto();
|
||||
testroundtrip();
|
||||
|
||||
Reference in New Issue
Block a user