summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--indra/llcommon/lleventcoro.cpp50
-rw-r--r--indra/llcommon/llsdutil.cpp67
-rw-r--r--indra/llcommon/llsdutil.h25
3 files changed, 97 insertions, 45 deletions
diff --git a/indra/llcommon/lleventcoro.cpp b/indra/llcommon/lleventcoro.cpp
index 56367b8f54..43e41f250d 100644
--- a/indra/llcommon/lleventcoro.cpp
+++ b/indra/llcommon/lleventcoro.cpp
@@ -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
diff --git a/indra/llcommon/llsdutil.cpp b/indra/llcommon/llsdutil.cpp
index 9d00395c0a..ad27f19e85 100644
--- a/indra/llcommon/llsdutil.cpp
+++ b/indra/llcommon/llsdutil.cpp
@@ -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
diff --git a/indra/llcommon/llsdutil.h b/indra/llcommon/llsdutil.h
index 01ab6bcb8d..e659aa574e 100644
--- a/indra/llcommon/llsdutil.h
+++ b/indra/llcommon/llsdutil.h
@@ -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
*****************************************************************************/