SL-11216: Add llsd::drill() function to drill into an LLSD blob.
We include both const and non-const overloads. The latter returns LLSD&, so you can assign to the located element. In fact we already implemented the non-const logic in a less public form as storeToLLSDPath() in lleventcoro.cpp. Reimplement the latter to use the new llsd::drill() function.meow-7.2.2
parent
0bb6f754a1
commit
712a03300b
|
|
@ -36,6 +36,7 @@
|
|||
// external library headers
|
||||
// other Linden headers
|
||||
#include "llsdserialize.h"
|
||||
#include "llsdutil.h"
|
||||
#include "llerror.h"
|
||||
#include "llcoros.h"
|
||||
#include "llmake.h"
|
||||
|
|
@ -92,57 +93,16 @@ std::string listenerNameForCoro()
|
|||
* In the degenerate case in which @a path is an empty array, @a dest will
|
||||
* @em become @a value rather than @em containing it.
|
||||
*/
|
||||
void storeToLLSDPath(LLSD& dest, const LLSD& rawPath, const LLSD& value)
|
||||
void storeToLLSDPath(LLSD& dest, const LLSD& path, const LLSD& value)
|
||||
{
|
||||
if (rawPath.isUndefined())
|
||||
if (path.isUndefined())
|
||||
{
|
||||
// no-op case
|
||||
return;
|
||||
}
|
||||
|
||||
// Arrange to treat rawPath uniformly as an array. If it's not already an
|
||||
// array, store it as the only entry in one.
|
||||
LLSD path;
|
||||
if (rawPath.isArray())
|
||||
{
|
||||
path = rawPath;
|
||||
}
|
||||
else
|
||||
{
|
||||
path.append(rawPath);
|
||||
}
|
||||
|
||||
// Need to indicate a current destination -- but that current destination
|
||||
// needs to change as we step through the path array. Where normally we'd
|
||||
// use an LLSD& to capture a subscripted LLSD lvalue, this time we must
|
||||
// instead use a pointer -- since it must be reassigned.
|
||||
LLSD* pdest = &dest;
|
||||
|
||||
// Now loop through that array
|
||||
for (LLSD::Integer i = 0; i < path.size(); ++i)
|
||||
{
|
||||
if (path[i].isString())
|
||||
{
|
||||
// *pdest is an LLSD map
|
||||
pdest = &((*pdest)[path[i].asString()]);
|
||||
}
|
||||
else if (path[i].isInteger())
|
||||
{
|
||||
// *pdest is an LLSD array
|
||||
pdest = &((*pdest)[path[i].asInteger()]);
|
||||
}
|
||||
else
|
||||
{
|
||||
// What do we do with Real or Array or Map or ...?
|
||||
// As it's a coder error -- not a user error -- rub the coder's
|
||||
// face in it so it gets fixed.
|
||||
LL_ERRS("lleventcoro") << "storeToLLSDPath(" << dest << ", " << rawPath << ", " << value
|
||||
<< "): path[" << i << "] bad type " << path[i].type() << LL_ENDL;
|
||||
}
|
||||
}
|
||||
|
||||
// Here *pdest is where we should store value.
|
||||
*pdest = value;
|
||||
// Drill down to where we should store 'value'.
|
||||
llsd::drill(dest, path) = value;
|
||||
}
|
||||
|
||||
/// For LLCoros::Future<LLSD>::make_callback(), the callback has a signature
|
||||
|
|
|
|||
|
|
@ -681,3 +681,70 @@ bool llsd_equals(const LLSD& lhs, const LLSD& rhs, int bits)
|
|||
return false; // pacify the compiler
|
||||
}
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
* llsd::drill()
|
||||
*****************************************************************************/
|
||||
namespace llsd
|
||||
{
|
||||
|
||||
LLSD& drill(LLSD& blob, const LLSD& rawPath)
|
||||
{
|
||||
// Treat rawPath uniformly as an array. If it's not already an array,
|
||||
// store it as the only entry in one.
|
||||
LLSD path;
|
||||
if (rawPath.isArray())
|
||||
{
|
||||
path = rawPath;
|
||||
}
|
||||
else
|
||||
{
|
||||
path.append(rawPath);
|
||||
}
|
||||
|
||||
// Need to indicate a current destination -- but that current destination
|
||||
// must change as we step through the path array. Where normally we'd use
|
||||
// an LLSD& to capture a subscripted LLSD lvalue, this time we must
|
||||
// instead use a pointer -- since it must be reassigned.
|
||||
// Start by pointing to the input blob exactly as is.
|
||||
LLSD* located{&blob};
|
||||
|
||||
// Extract the element of interest by walking path. Use an explicit index
|
||||
// so that, in case of a bogus type in path, we can identify the specific
|
||||
// path entry that's bad.
|
||||
for (LLSD::Integer i = 0; i < path.size(); ++i)
|
||||
{
|
||||
const LLSD& key{path[i]};
|
||||
if (key.isString())
|
||||
{
|
||||
// a string path element is a map key
|
||||
located = &((*located)[key.asString()]);
|
||||
}
|
||||
else if (key.isInteger())
|
||||
{
|
||||
// an integer path element is an array index
|
||||
located = &((*located)[key.asInteger()]);
|
||||
}
|
||||
else
|
||||
{
|
||||
// What do we do with Real or Array or Map or ...?
|
||||
// As it's a coder error -- not a user error -- rub the coder's
|
||||
// face in it so it gets fixed.
|
||||
LL_ERRS("llsdutil") << "drill(" << blob << ", " << rawPath
|
||||
<< "): path[" << i << "] bad type "
|
||||
<< sTypes.lookup(key.type()) << LL_ENDL;
|
||||
}
|
||||
}
|
||||
|
||||
// dereference the pointer to return a reference to the element we found
|
||||
return *located;
|
||||
}
|
||||
|
||||
LLSD drill(const LLSD& blob, const LLSD& path)
|
||||
{
|
||||
// non-const drill() does exactly what we want. Temporarily cast away
|
||||
// const-ness and use that.
|
||||
return drill(const_cast<LLSD&>(blob), path);
|
||||
}
|
||||
|
||||
} // namespace llsd
|
||||
|
|
|
|||
|
|
@ -142,6 +142,31 @@ template<typename Input> LLSD llsd_copy_array(Input iter, Input end)
|
|||
return dest;
|
||||
}
|
||||
|
||||
namespace llsd
|
||||
{
|
||||
|
||||
/**
|
||||
* Drill down to locate an element in 'blob' according to 'path', where 'path'
|
||||
* is one of the following:
|
||||
*
|
||||
* - LLSD::String: 'blob' is an LLSD::Map. Find the entry with key 'path'.
|
||||
* - LLSD::Integer: 'blob' is an LLSD::Array. Find the entry with index 'path'.
|
||||
* - Any other 'path' type will be interpreted as LLSD::Array, and 'blob' is a
|
||||
* nested structure. For each element of 'path':
|
||||
* - If it's an LLSD::Integer, select the entry with that index from an
|
||||
* LLSD::Array at that level.
|
||||
* - If it's an LLSD::String, select the entry with that key from an
|
||||
* LLSD::Map at that level.
|
||||
* - Anything else is an error.
|
||||
*
|
||||
* By implication, if path.isUndefined() or otherwise equivalent to an empty
|
||||
* LLSD::Array, drill() returns 'blob' as is.
|
||||
*/
|
||||
LLSD drill(const LLSD& blob, const LLSD& path);
|
||||
LLSD& drill( LLSD& blob, const LLSD& path);
|
||||
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
* LLSDArray
|
||||
*****************************************************************************/
|
||||
|
|
|
|||
Loading…
Reference in New Issue