mirror of
https://github.com/XRPLF/rippled.git
synced 2025-12-06 17:27:55 +00:00
Move streaming Json objects to ripple/json.
This commit is contained in:
@@ -85,11 +85,11 @@ class HandlerTable {
|
||||
assert (table_.find(HandlerImpl::name()) == table_.end());
|
||||
|
||||
Handler h;
|
||||
h.name_ = HandlerImpl::name(),
|
||||
h.valueMethod_ = &handle<Json::Value, HandlerImpl>,
|
||||
h.role_ = HandlerImpl::role(),
|
||||
h.condition_ = HandlerImpl::condition(),
|
||||
h.objectMethod_ = &handle<Object, HandlerImpl>;
|
||||
h.name_ = HandlerImpl::name();
|
||||
h.valueMethod_ = &handle<Json::Value, HandlerImpl>;
|
||||
h.role_ = HandlerImpl::role();
|
||||
h.condition_ = HandlerImpl::condition();
|
||||
h.objectMethod_ = &handle<Json::Object, HandlerImpl>;
|
||||
|
||||
table_[HandlerImpl::name()] = h;
|
||||
};
|
||||
|
||||
@@ -24,11 +24,13 @@
|
||||
#include <ripple/rpc/RPCHandler.h>
|
||||
#include <ripple/rpc/Status.h>
|
||||
|
||||
namespace Json {
|
||||
class Object;
|
||||
}
|
||||
|
||||
namespace ripple {
|
||||
namespace RPC {
|
||||
|
||||
class Object;
|
||||
|
||||
// Under what condition can we call this RPC?
|
||||
enum Condition {
|
||||
NO_CONDITION = 0,
|
||||
@@ -46,7 +48,7 @@ struct Handler
|
||||
Method<Json::Value> valueMethod_;
|
||||
Role role_;
|
||||
RPC::Condition condition_;
|
||||
Method<Object> objectMethod_;
|
||||
Method<Json::Object> objectMethod_;
|
||||
};
|
||||
|
||||
const Handler* getHandler (std::string const&);
|
||||
|
||||
@@ -1,161 +0,0 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
This file is part of rippled: https://github.com/ripple/rippled
|
||||
Copyright (c) 2012, 2013 Ripple Labs Inc.
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
#include <BeastConfig.h>
|
||||
#include <ripple/rpc/impl/JsonObject.h>
|
||||
|
||||
namespace ripple {
|
||||
namespace RPC {
|
||||
|
||||
Collection::Collection (Collection* parent, Writer* writer)
|
||||
: parent_ (parent), writer_ (writer), enabled_ (true)
|
||||
{
|
||||
checkWritable ("Collection::Collection()");
|
||||
if (parent_)
|
||||
{
|
||||
check (parent_->enabled_, "Parent not enabled in constructor");
|
||||
parent_->enabled_ = false;
|
||||
}
|
||||
}
|
||||
|
||||
Collection::~Collection ()
|
||||
{
|
||||
if (writer_)
|
||||
writer_->finish ();
|
||||
if (parent_)
|
||||
parent_->enabled_ = true;
|
||||
}
|
||||
|
||||
Collection& Collection::operator= (Collection&& that) noexcept
|
||||
{
|
||||
parent_ = that.parent_;
|
||||
writer_ = that.writer_;
|
||||
enabled_ = that.enabled_;
|
||||
|
||||
that.parent_ = nullptr;
|
||||
that.writer_ = nullptr;
|
||||
that.enabled_ = false;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
Collection::Collection (Collection&& that) noexcept
|
||||
{
|
||||
*this = std::move (that);
|
||||
}
|
||||
|
||||
void Collection::checkWritable (std::string const& label)
|
||||
{
|
||||
if (!enabled_)
|
||||
throw JsonException (label + ": not enabled");
|
||||
if (!writer_)
|
||||
throw JsonException (label + ": not writable");
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
Object::Root::Root (Writer& w) : Object (nullptr, &w)
|
||||
{
|
||||
writer_->startRoot (Writer::object);
|
||||
}
|
||||
|
||||
Object Object::setObject (std::string const& key)
|
||||
{
|
||||
checkWritable ("Object::setObject");
|
||||
if (writer_)
|
||||
writer_->startSet (Writer::object, key);
|
||||
return Object (this, writer_);
|
||||
}
|
||||
|
||||
Array Object::setArray (std::string const& key) {
|
||||
checkWritable ("Object::setArray");
|
||||
if (writer_)
|
||||
writer_->startSet (Writer::array, key);
|
||||
return Array (this, writer_);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
Object Array::appendObject ()
|
||||
{
|
||||
checkWritable ("Array::appendObject");
|
||||
if (writer_)
|
||||
writer_->startAppend (Writer::object);
|
||||
return Object (this, writer_);
|
||||
}
|
||||
|
||||
Array Array::appendArray ()
|
||||
{
|
||||
checkWritable ("Array::makeArray");
|
||||
if (writer_)
|
||||
writer_->startAppend (Writer::array);
|
||||
return Array (this, writer_);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
Object::Proxy::Proxy (Object& object, std::string const& key)
|
||||
: object_ (object)
|
||||
, key_ (key)
|
||||
{
|
||||
}
|
||||
|
||||
Object::Proxy Object::operator[] (std::string const& key)
|
||||
{
|
||||
return Proxy (*this, key);
|
||||
}
|
||||
|
||||
Object::Proxy Object::operator[] (Json::StaticString const& key)
|
||||
{
|
||||
return Proxy (*this, std::string (key));
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
template <class Object>
|
||||
void doCopyFrom (Object& to, Json::Value const& from)
|
||||
{
|
||||
assert (from.isObject());
|
||||
auto members = from.getMemberNames();
|
||||
for (auto& m: members)
|
||||
to[m] = from[m];
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void copyFrom (Json::Value& to, Json::Value const& from)
|
||||
{
|
||||
if (to.empty()) // Short circuit this very common case.
|
||||
to = from;
|
||||
else
|
||||
doCopyFrom (to, from);
|
||||
}
|
||||
|
||||
void copyFrom (Object& to, Json::Value const& from)
|
||||
{
|
||||
doCopyFrom (to, from);
|
||||
}
|
||||
|
||||
WriterObject stringWriterObject (std::string& s)
|
||||
{
|
||||
return WriterObject (stringOutput (s));
|
||||
}
|
||||
|
||||
} // RPC
|
||||
} // ripple
|
||||
@@ -1,495 +0,0 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
This file is part of rippled: https://github.com/ripple/rippled
|
||||
Copyright (c) 2012, 2013 Ripple Labs Inc.
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
#ifndef RIPPLE_RPC_JSONOBJECT_H_INCLUDED
|
||||
#define RIPPLE_RPC_JSONOBJECT_H_INCLUDED
|
||||
|
||||
#include <ripple/rpc/impl/JsonWriter.h>
|
||||
|
||||
namespace ripple {
|
||||
namespace RPC {
|
||||
|
||||
/**
|
||||
Collection is a base class for Array and Object, classes which provide the
|
||||
facade of JSON collections for the O(1) JSON writer, while still using no
|
||||
heap memory and only a very small amount of stack.
|
||||
|
||||
From http://json.org, JSON has two types of collection: array, and object.
|
||||
Everything else is a *scalar* - a number, a string, a boolean, the special
|
||||
value null, or a legacy Json::Value.
|
||||
|
||||
Collections must write JSON "as-it-goes" in order to get the strong
|
||||
performance guarantees. This puts restrictions upon API users:
|
||||
|
||||
1. Only one collection can be open for change at any one time.
|
||||
|
||||
This condition is enforced automatically and a JsonException thrown if it
|
||||
is violated.
|
||||
|
||||
2. A tag may only be used once in an Object.
|
||||
|
||||
Some objects have many tags, so this condition might be a little
|
||||
expensive. Enforcement of this condition is turned on in debug builds and
|
||||
a JsonException is thrown when the tag is added for a second time.
|
||||
|
||||
Code samples:
|
||||
|
||||
Writer writer;
|
||||
|
||||
// An empty object.
|
||||
{
|
||||
Object::Root (writer);
|
||||
}
|
||||
// Outputs {}
|
||||
|
||||
// An object with one scalar value.
|
||||
{
|
||||
Object::Root root (writer);
|
||||
write["hello"] = "world";
|
||||
}
|
||||
// Outputs {"hello":"world"}
|
||||
|
||||
// Same, using chaining.
|
||||
{
|
||||
Object::Root (writer)["hello"] = "world";
|
||||
}
|
||||
// Output is the same.
|
||||
|
||||
// Add several scalars, with chaining.
|
||||
{
|
||||
Object::Root (writer)
|
||||
.set ("hello", "world")
|
||||
.set ("flag", false)
|
||||
.set ("x", 42);
|
||||
}
|
||||
// Outputs {"hello":"world","flag":false,"x":42}
|
||||
|
||||
// Add an array.
|
||||
{
|
||||
Object::Root root (writer);
|
||||
{
|
||||
auto array = root.setArray ("hands");
|
||||
array.append ("left");
|
||||
array.append ("right");
|
||||
}
|
||||
}
|
||||
// Outputs {"hands":["left", "right"]}
|
||||
|
||||
// Same, using chaining.
|
||||
{
|
||||
Object::Root (writer)
|
||||
.setArray ("hands")
|
||||
.append ("left")
|
||||
.append ("right");
|
||||
}
|
||||
// Output is the same.
|
||||
|
||||
// Add an object.
|
||||
{
|
||||
Object::Root root (writer);
|
||||
{
|
||||
auto object = root.setObject ("hands");
|
||||
object["left"] = false;
|
||||
object["right"] = true;
|
||||
}
|
||||
}
|
||||
// Outputs {"hands":{"left":false,"right":true}}
|
||||
|
||||
// Same, using chaining.
|
||||
{
|
||||
Object::Root (writer)
|
||||
.setObject ("hands")
|
||||
.set ("left", false)
|
||||
.set ("right", true);
|
||||
}
|
||||
}
|
||||
// Outputs {"hands":{"left":false,"right":true}}
|
||||
|
||||
|
||||
Typical ways to make mistakes and get a JsonException:
|
||||
|
||||
Writer writer;
|
||||
Object::Root root (writer);
|
||||
|
||||
// Repeat a tag.
|
||||
{
|
||||
root ["hello"] = "world";
|
||||
root ["hello"] = "there"; // THROWS! in a debug build.
|
||||
}
|
||||
|
||||
// Open a subcollection, then set something else.
|
||||
{
|
||||
auto object = root.setObject ("foo");
|
||||
root ["hello"] = "world"; // THROWS!
|
||||
}
|
||||
|
||||
// Open two subcollections at a time.
|
||||
{
|
||||
auto object = root.setObject ("foo");
|
||||
auto array = root.setArray ("bar"); // THROWS!!
|
||||
}
|
||||
|
||||
For more examples, check the unit tests.
|
||||
*/
|
||||
|
||||
class Collection
|
||||
{
|
||||
public:
|
||||
Collection (Collection&& c) noexcept;
|
||||
Collection& operator= (Collection&& c) noexcept;
|
||||
Collection() = delete;
|
||||
|
||||
~Collection();
|
||||
|
||||
protected:
|
||||
// A null parent means "no parent at all".
|
||||
// Writers cannot be null.
|
||||
Collection (Collection* parent, Writer*);
|
||||
void checkWritable (std::string const& label);
|
||||
|
||||
Collection* parent_;
|
||||
Writer* writer_;
|
||||
bool enabled_;
|
||||
};
|
||||
|
||||
class Array;
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/** Represents a JSON object being written to a Writer. */
|
||||
class Object : protected Collection
|
||||
{
|
||||
public:
|
||||
/** Object::Root is the only Collection that has a public constructor. */
|
||||
class Root;
|
||||
|
||||
/** Set a scalar value in the Object for a key.
|
||||
|
||||
A JSON scalar is a single value - a number, string, boolean, nullptr or
|
||||
a Json::Value.
|
||||
|
||||
`set()` throws an exception if this object is disabled (which means that
|
||||
one of its children is enabled).
|
||||
|
||||
In a debug build, `set()` also throws an exception if the key has
|
||||
already been set() before.
|
||||
|
||||
An operator[] is provided to allow writing `object["key"] = scalar;`.
|
||||
*/
|
||||
template <typename Scalar>
|
||||
void set (std::string const& key, Scalar const&);
|
||||
|
||||
void set (std::string const& key, Json::Value const&);
|
||||
|
||||
// Detail class and method used to implement operator[].
|
||||
class Proxy;
|
||||
|
||||
Proxy operator[] (std::string const& key);
|
||||
Proxy operator[] (Json::StaticString const& key);
|
||||
|
||||
/** Make a new Object at a key and return it.
|
||||
|
||||
This Object is disabled until that sub-object is destroyed.
|
||||
Throws an exception if this Object was already disabled.
|
||||
*/
|
||||
Object setObject (std::string const& key);
|
||||
|
||||
/** Make a new Array at a key and return it.
|
||||
|
||||
This Object is disabled until that sub-array is destroyed.
|
||||
Throws an exception if this Object was already disabled.
|
||||
*/
|
||||
Array setArray (std::string const& key);
|
||||
|
||||
protected:
|
||||
friend class Array;
|
||||
Object (Collection* parent, Writer* w) : Collection (parent, w) {}
|
||||
};
|
||||
|
||||
class Object::Root : public Object
|
||||
{
|
||||
public:
|
||||
/** Each Object::Root must be constructed with its own unique Writer. */
|
||||
Root (Writer&);
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/** Represents a JSON array being written to a Writer. */
|
||||
class Array : private Collection
|
||||
{
|
||||
public:
|
||||
/** Append a scalar to the Arrary.
|
||||
|
||||
Throws an exception if this array is disabled (which means that one of
|
||||
its sub-collections is enabled).
|
||||
*/
|
||||
template <typename Scalar>
|
||||
void append (Scalar const&);
|
||||
|
||||
/**
|
||||
Appends a Json::Value to an array.
|
||||
Throws an exception if this Array was disabled.
|
||||
*/
|
||||
void append (Json::Value const&);
|
||||
|
||||
/** Append a new Object and return it.
|
||||
|
||||
This Array is disabled until that sub-object is destroyed.
|
||||
Throws an exception if this Array was disabled.
|
||||
*/
|
||||
Object appendObject ();
|
||||
|
||||
/** Append a new Array and return it.
|
||||
|
||||
This Array is disabled until that sub-array is destroyed.
|
||||
Throws an exception if this Array was already disabled.
|
||||
*/
|
||||
Array appendArray ();
|
||||
|
||||
protected:
|
||||
friend class Object;
|
||||
Array (Collection* parent, Writer* w) : Collection (parent, w) {}
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
// Generic accessor functions to allow Json::Value and Collection to
|
||||
// interoperate.
|
||||
|
||||
/** Add a new subarray at a named key in a Json object. */
|
||||
Json::Value& setArray (Json::Value&, Json::StaticString const& key);
|
||||
|
||||
/** Add a new subarray at a named key in a Json object. */
|
||||
Array setArray (Object&, Json::StaticString const& key);
|
||||
|
||||
|
||||
/** Add a new subobject at a named key in a Json object. */
|
||||
Json::Value& addObject (Json::Value&, Json::StaticString const& key);
|
||||
|
||||
/** Add a new subobject at a named key in a Json object. */
|
||||
Object addObject (Object&, Json::StaticString const& key);
|
||||
|
||||
|
||||
/** Append a new subarray to a Json array. */
|
||||
Json::Value& appendArray (Json::Value&);
|
||||
|
||||
/** Append a new subarray to a Json array. */
|
||||
Array appendArray (Array&);
|
||||
|
||||
|
||||
/** Append a new subobject to a Json object. */
|
||||
Json::Value& appendObject (Json::Value&);
|
||||
|
||||
/** Append a new subobject to a Json object. */
|
||||
Object appendObject (Array&);
|
||||
|
||||
|
||||
/** Copy all the keys and values from one object into another. */
|
||||
void copyFrom (Json::Value& to, Json::Value const& from);
|
||||
|
||||
/** Copy all the keys and values from one object into another. */
|
||||
void copyFrom (Object& to, Json::Value const& from);
|
||||
|
||||
|
||||
/** An Object that contains its own Writer. */
|
||||
class WriterObject
|
||||
{
|
||||
public:
|
||||
WriterObject (Output const& output)
|
||||
: writer_ (std::make_unique<Writer> (output)),
|
||||
object_ (std::make_unique<Object::Root> (*writer_))
|
||||
{
|
||||
}
|
||||
|
||||
#ifdef _MSC_VER
|
||||
WriterObject (WriterObject&& other) noexcept
|
||||
: writer_ (std::move (other.writer_)),
|
||||
object_ (std::move (other.object_))
|
||||
{
|
||||
}
|
||||
#endif
|
||||
|
||||
Object* operator->()
|
||||
{
|
||||
return object_.get();
|
||||
}
|
||||
|
||||
Object& operator*()
|
||||
{
|
||||
return *object_;
|
||||
}
|
||||
|
||||
private:
|
||||
std::unique_ptr <Writer> writer_;
|
||||
std::unique_ptr<Object::Root> object_;
|
||||
};
|
||||
|
||||
WriterObject stringWriterObject (std::string&);
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Implementation details.
|
||||
|
||||
// Detail class for Object::operator[].
|
||||
class Object::Proxy
|
||||
{
|
||||
private:
|
||||
Object& object_;
|
||||
std::string const key_;
|
||||
|
||||
public:
|
||||
Proxy (Object& object, std::string const& key);
|
||||
|
||||
template <class T>
|
||||
void operator= (T const& t)
|
||||
{
|
||||
object_.set (key_, t);
|
||||
}
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
template <typename Scalar>
|
||||
void Array::append (Scalar const& value)
|
||||
{
|
||||
checkWritable ("append");
|
||||
if (writer_)
|
||||
writer_->append (value);
|
||||
}
|
||||
|
||||
inline void Array::append (Json::Value const& v)
|
||||
{
|
||||
auto t = v.type();
|
||||
switch (t)
|
||||
{
|
||||
case Json::nullValue: return append (nullptr);
|
||||
case Json::intValue: return append (v.asInt());
|
||||
case Json::uintValue: return append (v.asUInt());
|
||||
case Json::realValue: return append (v.asDouble());
|
||||
case Json::stringValue: return append (v.asString());
|
||||
case Json::booleanValue: return append (v.asBool());
|
||||
|
||||
case Json::objectValue:
|
||||
{
|
||||
auto object = appendObject ();
|
||||
copyFrom (object, v);
|
||||
return;
|
||||
}
|
||||
|
||||
case Json::arrayValue:
|
||||
{
|
||||
auto array = appendArray ();
|
||||
for (auto& item: v)
|
||||
array.append (item);
|
||||
return;
|
||||
}
|
||||
}
|
||||
assert (false); // Can't get here.
|
||||
}
|
||||
|
||||
template <typename Scalar>
|
||||
void Object::set (std::string const& key, Scalar const& value)
|
||||
{
|
||||
checkWritable ("set");
|
||||
if (writer_)
|
||||
writer_->set (key, value);
|
||||
}
|
||||
|
||||
inline void Object::set (std::string const& k, Json::Value const& v)
|
||||
{
|
||||
auto t = v.type();
|
||||
switch (t)
|
||||
{
|
||||
case Json::nullValue: return set (k, nullptr);
|
||||
case Json::intValue: return set (k, v.asInt());
|
||||
case Json::uintValue: return set (k, v.asUInt());
|
||||
case Json::realValue: return set (k, v.asDouble());
|
||||
case Json::stringValue: return set (k, v.asString());
|
||||
case Json::booleanValue: return set (k, v.asBool());
|
||||
|
||||
case Json::objectValue:
|
||||
{
|
||||
auto object = setObject (k);
|
||||
copyFrom (object, v);
|
||||
return;
|
||||
}
|
||||
|
||||
case Json::arrayValue:
|
||||
{
|
||||
auto array = setArray (k);
|
||||
for (auto& item: v)
|
||||
array.append (item);
|
||||
return;
|
||||
}
|
||||
}
|
||||
assert (false); // Can't get here.
|
||||
}
|
||||
|
||||
inline
|
||||
Json::Value& setArray (Json::Value& json, Json::StaticString const& key)
|
||||
{
|
||||
return (json[key] = Json::arrayValue);
|
||||
}
|
||||
|
||||
inline
|
||||
Array setArray (Object& json, Json::StaticString const& key)
|
||||
{
|
||||
return json.setArray (std::string (key));
|
||||
}
|
||||
|
||||
inline
|
||||
Json::Value& addObject (Json::Value& json, Json::StaticString const& key)
|
||||
{
|
||||
return (json[key] = Json::objectValue);
|
||||
}
|
||||
|
||||
inline
|
||||
Object addObject (Object& object, Json::StaticString const& key)
|
||||
{
|
||||
return object.setObject (std::string (key));
|
||||
}
|
||||
|
||||
inline
|
||||
Json::Value& appendArray (Json::Value& json)
|
||||
{
|
||||
return json.append (Json::arrayValue);
|
||||
}
|
||||
|
||||
inline
|
||||
Array appendArray (Array& json)
|
||||
{
|
||||
return json.appendArray ();
|
||||
}
|
||||
|
||||
inline
|
||||
Json::Value& appendObject (Json::Value& json)
|
||||
{
|
||||
return json.append (Json::objectValue);
|
||||
}
|
||||
|
||||
inline
|
||||
Object appendObject (Array& json)
|
||||
{
|
||||
return json.appendObject ();
|
||||
}
|
||||
|
||||
} // RPC
|
||||
} // ripple
|
||||
|
||||
#endif
|
||||
@@ -1,319 +0,0 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
This file is part of rippled: https://github.com/ripple/rippled
|
||||
Copyright (c) 2012, 2013 Ripple Labs Inc.
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
#include <BeastConfig.h>
|
||||
#include <ripple/rpc/impl/JsonWriter.h>
|
||||
#include <ripple/rpc/impl/WriteJson.h>
|
||||
#include <beast/unit_test/suite.h>
|
||||
|
||||
namespace ripple {
|
||||
namespace RPC {
|
||||
|
||||
namespace {
|
||||
|
||||
std::map <char, const char*> jsonSpecialCharacterEscape = {
|
||||
{'"', "\\\""},
|
||||
{'\\', "\\\\"},
|
||||
{'/', "\\/"},
|
||||
{'\b', "\\b"},
|
||||
{'\f', "\\f"},
|
||||
{'\n', "\\n"},
|
||||
{'\r', "\\r"},
|
||||
{'\t', "\\t"}
|
||||
};
|
||||
|
||||
static size_t const jsonEscapeLength = 2;
|
||||
|
||||
// All other JSON punctuation.
|
||||
const char closeBrace = '}';
|
||||
const char closeBracket = ']';
|
||||
const char colon = ':';
|
||||
const char comma = ',';
|
||||
const char openBrace = '{';
|
||||
const char openBracket = '[';
|
||||
const char quote = '"';
|
||||
|
||||
const std::string none;
|
||||
|
||||
static auto const integralFloatsBecomeInts = false;
|
||||
|
||||
size_t lengthWithoutTrailingZeros (std::string const& s)
|
||||
{
|
||||
auto dotPos = s.find ('.');
|
||||
if (dotPos == std::string::npos)
|
||||
return s.size();
|
||||
|
||||
auto lastNonZero = s.find_last_not_of ('0');
|
||||
auto hasDecimals = dotPos != lastNonZero;
|
||||
|
||||
if (hasDecimals)
|
||||
return lastNonZero + 1;
|
||||
|
||||
if (integralFloatsBecomeInts || lastNonZero + 2 > s.size())
|
||||
return lastNonZero;
|
||||
|
||||
return lastNonZero + 2;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
class Writer::Impl
|
||||
{
|
||||
public:
|
||||
Impl (Output const& output) : output_(output) {}
|
||||
~Impl() = default;
|
||||
|
||||
Impl(Impl&&) = delete;
|
||||
Impl& operator=(Impl&&) = delete;
|
||||
|
||||
bool empty() const { return stack_.empty (); }
|
||||
|
||||
void start (CollectionType ct)
|
||||
{
|
||||
char ch = (ct == array) ? openBracket : openBrace;
|
||||
output ({&ch, 1});
|
||||
stack_.push (Collection());
|
||||
stack_.top().type = ct;
|
||||
}
|
||||
|
||||
void output (boost::string_ref const& bytes)
|
||||
{
|
||||
markStarted ();
|
||||
output_ (bytes);
|
||||
}
|
||||
|
||||
void stringOutput (boost::string_ref const& bytes)
|
||||
{
|
||||
markStarted ();
|
||||
std::size_t position = 0, writtenUntil = 0;
|
||||
|
||||
output_ ({"e, 1});
|
||||
auto data = bytes.data();
|
||||
for (; position < bytes.size(); ++position)
|
||||
{
|
||||
auto i = jsonSpecialCharacterEscape.find (data[position]);
|
||||
if (i != jsonSpecialCharacterEscape.end ())
|
||||
{
|
||||
if (writtenUntil < position)
|
||||
{
|
||||
output_ ({data + writtenUntil, position - writtenUntil});
|
||||
}
|
||||
output_ ({i->second, jsonEscapeLength});
|
||||
writtenUntil = position + 1;
|
||||
};
|
||||
}
|
||||
if (writtenUntil < position)
|
||||
output_ ({data + writtenUntil, position - writtenUntil});
|
||||
output_ ({"e, 1});
|
||||
}
|
||||
|
||||
void markStarted ()
|
||||
{
|
||||
check (!isFinished(), "isFinished() in output.");
|
||||
isStarted_ = true;
|
||||
}
|
||||
|
||||
void nextCollectionEntry (CollectionType type, std::string const& message)
|
||||
{
|
||||
check (!empty() , "empty () in " + message);
|
||||
|
||||
auto t = stack_.top ().type;
|
||||
if (t != type)
|
||||
{
|
||||
check (false, "Not an " +
|
||||
((type == array ? "array: " : "object: ") + message));
|
||||
}
|
||||
if (stack_.top ().isFirst)
|
||||
stack_.top ().isFirst = false;
|
||||
else
|
||||
output_ ({&comma, 1});
|
||||
}
|
||||
|
||||
void writeObjectTag (std::string const& tag)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
// Make sure we haven't already seen this tag.
|
||||
auto& tags = stack_.top ().tags;
|
||||
check (tags.find (tag) == tags.end (), "Already seen tag " + tag);
|
||||
tags.insert (tag);
|
||||
#endif
|
||||
|
||||
stringOutput (tag);
|
||||
output_ ({&colon, 1});
|
||||
}
|
||||
|
||||
bool isFinished() const
|
||||
{
|
||||
return isStarted_ && empty();
|
||||
}
|
||||
|
||||
void finish ()
|
||||
{
|
||||
check (!empty(), "Empty stack in finish()");
|
||||
|
||||
auto isArray = stack_.top().type == array;
|
||||
auto ch = isArray ? closeBracket : closeBrace;
|
||||
output_ ({&ch, 1});
|
||||
stack_.pop();
|
||||
}
|
||||
|
||||
void finishAll ()
|
||||
{
|
||||
if (isStarted_)
|
||||
{
|
||||
while (!isFinished())
|
||||
finish();
|
||||
}
|
||||
}
|
||||
|
||||
Output const& getOutput() const { return output_; }
|
||||
|
||||
private:
|
||||
// JSON collections are either arrrays, or objects.
|
||||
struct Collection
|
||||
{
|
||||
/** What type of collection are we in? */
|
||||
Writer::CollectionType type;
|
||||
|
||||
/** Is this the first entry in a collection?
|
||||
* If false, we have to emit a , before we write the next entry. */
|
||||
bool isFirst = true;
|
||||
|
||||
#ifdef DEBUG
|
||||
/** What tags have we already seen in this collection? */
|
||||
std::set <std::string> tags;
|
||||
#endif
|
||||
};
|
||||
|
||||
using Stack = std::stack <Collection, std::vector<Collection>>;
|
||||
|
||||
Output output_;
|
||||
Stack stack_;
|
||||
|
||||
bool isStarted_ = false;
|
||||
};
|
||||
|
||||
Writer::Writer (Output const &output)
|
||||
: impl_(std::make_unique <Impl> (output))
|
||||
{
|
||||
}
|
||||
|
||||
Writer::~Writer()
|
||||
{
|
||||
if (impl_)
|
||||
impl_->finishAll ();
|
||||
}
|
||||
|
||||
Writer::Writer(Writer&& w) noexcept
|
||||
{
|
||||
impl_ = std::move (w.impl_);
|
||||
}
|
||||
|
||||
Writer& Writer::operator=(Writer&& w) noexcept
|
||||
{
|
||||
impl_ = std::move (w.impl_);
|
||||
return *this;
|
||||
}
|
||||
|
||||
void Writer::output (char const* s)
|
||||
{
|
||||
impl_->stringOutput (s);
|
||||
}
|
||||
|
||||
void Writer::output (std::string const& s)
|
||||
{
|
||||
impl_->stringOutput (s);
|
||||
}
|
||||
|
||||
void Writer::output (Json::Value const& value)
|
||||
{
|
||||
impl_->markStarted();
|
||||
writeJson (value, impl_->getOutput());
|
||||
}
|
||||
|
||||
template <>
|
||||
void Writer::output (float f)
|
||||
{
|
||||
auto s = to_string (f);
|
||||
impl_->output ({s.data (), lengthWithoutTrailingZeros (s)});
|
||||
}
|
||||
|
||||
template <>
|
||||
void Writer::output (double f)
|
||||
{
|
||||
auto s = to_string (f);
|
||||
impl_->output ({s.data (), lengthWithoutTrailingZeros (s)});
|
||||
}
|
||||
|
||||
template <>
|
||||
void Writer::output (std::nullptr_t)
|
||||
{
|
||||
impl_->output ("null");
|
||||
}
|
||||
|
||||
void Writer::implOutput (std::string const& s)
|
||||
{
|
||||
impl_->output (s);
|
||||
}
|
||||
|
||||
void Writer::finishAll ()
|
||||
{
|
||||
if (impl_)
|
||||
impl_->finishAll ();
|
||||
}
|
||||
|
||||
void Writer::rawAppend()
|
||||
{
|
||||
impl_->nextCollectionEntry (array, "append");
|
||||
}
|
||||
|
||||
void Writer::rawSet (std::string const& tag)
|
||||
{
|
||||
check (!tag.empty(), "Tag can't be empty");
|
||||
|
||||
impl_->nextCollectionEntry (object, "set");
|
||||
impl_->writeObjectTag (tag);
|
||||
}
|
||||
|
||||
void Writer::startRoot (CollectionType type)
|
||||
{
|
||||
impl_->start (type);
|
||||
}
|
||||
|
||||
void Writer::startAppend (CollectionType type)
|
||||
{
|
||||
impl_->nextCollectionEntry (array, "startAppend");
|
||||
impl_->start (type);
|
||||
}
|
||||
|
||||
void Writer::startSet (CollectionType type, std::string const& key)
|
||||
{
|
||||
impl_->nextCollectionEntry (object, "startSet");
|
||||
impl_->writeObjectTag (key);
|
||||
impl_->start (type);
|
||||
}
|
||||
|
||||
void Writer::finish ()
|
||||
{
|
||||
if (impl_)
|
||||
impl_->finish ();
|
||||
}
|
||||
|
||||
} // RPC
|
||||
} // ripple
|
||||
@@ -1,250 +0,0 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
This file is part of rippled: https://github.com/ripple/rippled
|
||||
Copyright (c) 2012, 2013 Ripple Labs Inc.
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
#ifndef RIPPLE_RPC_JSONWRITER_H_INCLUDED
|
||||
#define RIPPLE_RPC_JSONWRITER_H_INCLUDED
|
||||
|
||||
#include <ripple/basics/ToString.h>
|
||||
#include <ripple/protocol/ErrorCodes.h>
|
||||
#include <ripple/rpc/Output.h>
|
||||
#include <ripple/protocol/ErrorCodes.h>
|
||||
|
||||
namespace ripple {
|
||||
namespace RPC {
|
||||
|
||||
/**
|
||||
* Writer implements an O(1)-space, O(1)-granular output JSON writer.
|
||||
*
|
||||
* O(1)-space means that it uses a fixed amount of memory, and that there are
|
||||
* no heap allocations at each step of the way.
|
||||
*
|
||||
* O(1)-granular output means the writer only outputs in small segments of a
|
||||
* bounded size, using a bounded number of CPU cycles in doing so. This is
|
||||
* very helpful in scheduling long jobs.
|
||||
*
|
||||
* The tradeoff is that you have to fill items in the JSON tree as you go,
|
||||
* and you can never go backward.
|
||||
*
|
||||
* Writer can write single JSON tokens, but the typical use is to write out an
|
||||
* entire JSON object. For example:
|
||||
*
|
||||
* {
|
||||
* Writer w (out);
|
||||
*
|
||||
* w.startObject (); // Start the root object.
|
||||
* w.set ("hello", "world");
|
||||
* w.set ("goodbye", 23);
|
||||
* w.finishObject (); // Finish the root object.
|
||||
* }
|
||||
*
|
||||
* which outputs the string
|
||||
*
|
||||
* {"hello":"world","goodbye":23}
|
||||
*
|
||||
* There can be an object inside an object:
|
||||
*
|
||||
* {
|
||||
* Writer w (out);
|
||||
*
|
||||
* w.startObject (); // Start the root object.
|
||||
* w.set ("hello", "world");
|
||||
*
|
||||
* w.startObjectSet ("subobject"); // Start a sub-object.
|
||||
* w.set ("goodbye", 23); // Add a key, value assignment.
|
||||
* w.finishObject (); // Finish the sub-object.
|
||||
*
|
||||
* w.finishObject (); // Finish the root-object.
|
||||
* }
|
||||
*
|
||||
* which outputs the string
|
||||
*
|
||||
* {"hello":"world","subobject":{"goodbye":23}}.
|
||||
*
|
||||
* Arrays work similarly
|
||||
*
|
||||
* {
|
||||
* Writer w (out);
|
||||
* w.startObject (); // Start the root object.
|
||||
*
|
||||
* w.startArraySet ("hello"); // Start an array.
|
||||
* w.append (23) // Append some items.
|
||||
* w.append ("skidoo")
|
||||
* w.finishArray (); // Finish the array.
|
||||
*
|
||||
* w.finishObject (); // Finish the root object.
|
||||
* }
|
||||
*
|
||||
* which outputs the string
|
||||
*
|
||||
* {"hello":[23,"skidoo"]}.
|
||||
*
|
||||
*
|
||||
* If you've reached the end of a long object, you can just use finishAll()
|
||||
* which finishes all arrays and objects that you have started.
|
||||
*
|
||||
* {
|
||||
* Writer w (out);
|
||||
* w.startObject (); // Start the root object.
|
||||
*
|
||||
* w.startArraySet ("hello"); // Start an array.
|
||||
* w.append (23) // Append an item.
|
||||
*
|
||||
* w.startArrayAppend () // Start a sub-array.
|
||||
* w.append ("one");
|
||||
* w.append ("two");
|
||||
*
|
||||
* w.startObjectAppend (); // Append a sub-object.
|
||||
* w.finishAll (); // Finish everything.
|
||||
* }
|
||||
*
|
||||
* which outputs the string
|
||||
*
|
||||
* {"hello":[23,["one","two",{}]]}.
|
||||
*
|
||||
* For convenience, the destructor of Writer calls w.finishAll() which makes
|
||||
* sure that all arrays and objects are closed. This means that you can throw
|
||||
* an exception, or have a coroutine simply clean up the stack, and be sure
|
||||
* that you do in fact generate a complete JSON object.
|
||||
*/
|
||||
|
||||
class Writer
|
||||
{
|
||||
public:
|
||||
enum CollectionType {array, object};
|
||||
|
||||
explicit Writer (Output const& output);
|
||||
Writer(Writer&&) noexcept;
|
||||
Writer& operator=(Writer&&) noexcept;
|
||||
|
||||
~Writer();
|
||||
|
||||
/** Start a new collection at the root level. */
|
||||
void startRoot (CollectionType);
|
||||
|
||||
/** Start a new collection inside an array. */
|
||||
void startAppend (CollectionType);
|
||||
|
||||
/** Start a new collection inside an object. */
|
||||
void startSet (CollectionType, std::string const& key);
|
||||
|
||||
/** Finish the collection most recently started. */
|
||||
void finish ();
|
||||
|
||||
/** Finish all objects and arrays. After finishArray() has been called, no
|
||||
* more operations can be performed. */
|
||||
void finishAll ();
|
||||
|
||||
/** Append a value to an array.
|
||||
*
|
||||
* Scalar must be a scalar - that is, a number, boolean, string, string
|
||||
* literal, nullptr or Json::Value
|
||||
*/
|
||||
template <typename Scalar>
|
||||
void append (Scalar t)
|
||||
{
|
||||
rawAppend();
|
||||
output (t);
|
||||
}
|
||||
|
||||
/** Add a comma before this next item if not the first item in an array.
|
||||
Useful if you are writing the actual array yourself. */
|
||||
void rawAppend();
|
||||
|
||||
/** Add a key, value assignment to an object.
|
||||
*
|
||||
* Scalar must be a scalar - that is, a number, boolean, string, string
|
||||
* literal, or nullptr.
|
||||
*
|
||||
* While the JSON spec doesn't explicitly disallow this, you should avoid
|
||||
* calling this method twice with the same tag for the same object.
|
||||
*
|
||||
* If CHECK_JSON_WRITER is defined, this function throws an exception if if
|
||||
* the tag you use has already been used in this object.
|
||||
*/
|
||||
template <typename Type>
|
||||
void set (std::string const& tag, Type t)
|
||||
{
|
||||
rawSet (tag);
|
||||
output (t);
|
||||
}
|
||||
|
||||
/** Emit just "tag": as part of an object. Useful if you are writing the
|
||||
actual value data yourself. */
|
||||
void rawSet (std::string const& key);
|
||||
|
||||
// You won't need to call anything below here until you are writing single
|
||||
// items (numbers, strings, bools, null) to a JSON stream.
|
||||
|
||||
/*** Output a string. */
|
||||
void output (std::string const&);
|
||||
|
||||
/*** Output a literal constant or C string. */
|
||||
void output (char const*);
|
||||
|
||||
/*** Output a Json::Value. */
|
||||
void output (Json::Value const&);
|
||||
|
||||
/** Output numbers or booleans. */
|
||||
template <typename Type>
|
||||
void output (Type t)
|
||||
{
|
||||
implOutput (to_string (t));
|
||||
}
|
||||
|
||||
/** Output an error code. */
|
||||
void output (error_code_i t)
|
||||
{
|
||||
output (int(t));
|
||||
}
|
||||
|
||||
void output (Json::StaticString const& t)
|
||||
{
|
||||
output (t.c_str());
|
||||
}
|
||||
|
||||
private:
|
||||
class Impl;
|
||||
std::unique_ptr <Impl> impl_;
|
||||
|
||||
void implOutput (std::string const&);
|
||||
};
|
||||
|
||||
class JsonException : public std::exception
|
||||
{
|
||||
public:
|
||||
explicit JsonException (std::string const& name) : name_(name) {}
|
||||
const char* what() const throw() override
|
||||
{
|
||||
return name_.c_str();
|
||||
}
|
||||
|
||||
private:
|
||||
std::string const name_;
|
||||
};
|
||||
|
||||
inline void check (bool condition, std::string const& message)
|
||||
{
|
||||
if (!condition)
|
||||
throw JsonException (message);
|
||||
}
|
||||
|
||||
} // RPC
|
||||
} // ripple
|
||||
|
||||
#endif
|
||||
@@ -22,12 +22,12 @@
|
||||
#include <ripple/rpc/Yield.h>
|
||||
#include <ripple/rpc/impl/Tuning.h>
|
||||
#include <ripple/rpc/impl/Handler.h>
|
||||
#include <ripple/rpc/impl/WriteJson.h>
|
||||
#include <ripple/app/ledger/LedgerMaster.h>
|
||||
#include <ripple/app/misc/NetworkOPs.h>
|
||||
#include <ripple/basics/Log.h>
|
||||
#include <ripple/core/Config.h>
|
||||
#include <ripple/core/JobQueue.h>
|
||||
#include <ripple/json/Object.h>
|
||||
#include <ripple/json/to_string.h>
|
||||
#include <ripple/net/InfoSub.h>
|
||||
#include <ripple/net/RPCErr.h>
|
||||
@@ -190,7 +190,7 @@ template <class Method, class Object>
|
||||
void getResult (
|
||||
Context& context, Method method, Object& object, std::string const& name)
|
||||
{
|
||||
auto&& result = addObject (object, jss::result);
|
||||
auto&& result = Json::addObject (object, jss::result);
|
||||
if (auto status = callMethod (context, method, name, result))
|
||||
{
|
||||
WriteLog (lsDEBUG, RPCErr) << "rpcError: " << status.toString();
|
||||
@@ -228,13 +228,13 @@ void executeRPC (
|
||||
boost::optional <Handler const&> handler;
|
||||
if (auto error = fillHandler (context, handler))
|
||||
{
|
||||
auto wo = stringWriterObject (output);
|
||||
auto&& sub = addObject (*wo, jss::result);
|
||||
auto wo = Json::stringWriterObject (output);
|
||||
auto&& sub = Json::addObject (*wo, jss::result);
|
||||
inject_error (error, sub);
|
||||
}
|
||||
else if (auto method = handler->objectMethod_)
|
||||
{
|
||||
auto wo = stringWriterObject (output);
|
||||
auto wo = Json::stringWriterObject (output);
|
||||
getResult (context, method, *wo, handler->name_);
|
||||
}
|
||||
else if (auto method = handler->valueMethod_)
|
||||
@@ -250,7 +250,7 @@ void executeRPC (
|
||||
{
|
||||
// Can't ever get here.
|
||||
assert (false);
|
||||
throw RPC::JsonException ("RPC handler with no method");
|
||||
throw Json::JsonException ("RPC handler with no method");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,113 +0,0 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
This file is part of rippled: https://github.com/ripple/rippled
|
||||
Copyright (c) 2012, 2013 Ripple Labs Inc.
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
#include <BeastConfig.h>
|
||||
#include <ripple/rpc/impl/WriteJson.h>
|
||||
#include <ripple/rpc/impl/JsonWriter.h>
|
||||
|
||||
namespace ripple {
|
||||
namespace RPC {
|
||||
|
||||
namespace {
|
||||
|
||||
void writeJson (Json::Value const& value, Writer& writer)
|
||||
{
|
||||
switch (value.type())
|
||||
{
|
||||
case Json::nullValue:
|
||||
{
|
||||
writer.output (nullptr);
|
||||
break;
|
||||
}
|
||||
|
||||
case Json::intValue:
|
||||
{
|
||||
writer.output (value.asInt());
|
||||
break;
|
||||
}
|
||||
|
||||
case Json::uintValue:
|
||||
{
|
||||
writer.output (value.asUInt());
|
||||
break;
|
||||
}
|
||||
|
||||
case Json::realValue:
|
||||
{
|
||||
writer.output (value.asDouble());
|
||||
break;
|
||||
}
|
||||
|
||||
case Json::stringValue:
|
||||
{
|
||||
writer.output (value.asString());
|
||||
break;
|
||||
}
|
||||
|
||||
case Json::booleanValue:
|
||||
{
|
||||
writer.output (value.asBool());
|
||||
break;
|
||||
}
|
||||
|
||||
case Json::arrayValue:
|
||||
{
|
||||
writer.startRoot (Writer::array);
|
||||
for (auto const& i: value)
|
||||
{
|
||||
writer.rawAppend();
|
||||
writeJson (i, writer);
|
||||
}
|
||||
writer.finish();
|
||||
break;
|
||||
}
|
||||
|
||||
case Json::objectValue:
|
||||
{
|
||||
writer.startRoot (Writer::object);
|
||||
auto members = value.getMemberNames ();
|
||||
for (auto const& tag: members)
|
||||
{
|
||||
writer.rawSet (tag);
|
||||
writeJson (value[tag], writer);
|
||||
}
|
||||
writer.finish();
|
||||
break;
|
||||
}
|
||||
} // switch
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
void writeJson (Json::Value const& value, Output const& out)
|
||||
{
|
||||
Writer writer (out);
|
||||
writeJson (value, writer);
|
||||
}
|
||||
|
||||
std::string jsonAsString (Json::Value const& value)
|
||||
{
|
||||
std::string s;
|
||||
Writer writer (stringOutput (s));
|
||||
writeJson (value, writer);
|
||||
return s;
|
||||
}
|
||||
|
||||
} // RPC
|
||||
} // ripple
|
||||
@@ -1,43 +0,0 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
This file is part of rippled: https://github.com/ripple/rippled
|
||||
Copyright (c) 2012, 2013 Ripple Labs Inc.
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
#ifndef RIPPLE_RPC_WRITEJSON_H_INCLUDED
|
||||
#define RIPPLE_RPC_WRITEJSON_H_INCLUDED
|
||||
|
||||
namespace ripple {
|
||||
namespace RPC {
|
||||
|
||||
/** Writes a minimal representation of a Json value to an Output in O(n) time.
|
||||
|
||||
Data is streamed right to the output, so only a marginal amount of memory is
|
||||
used. This can be very important for a very large Json::Value.
|
||||
*/
|
||||
void writeJson (Json::Value const&, Output const&);
|
||||
|
||||
/** Return the minimal string representation of a Json::Value in O(n) time.
|
||||
|
||||
This requires a memory allocation for the full size of the output.
|
||||
If possible, use write().
|
||||
*/
|
||||
std::string jsonAsString (Json::Value const&);
|
||||
|
||||
} // RPC
|
||||
} // ripple
|
||||
|
||||
#endif
|
||||
@@ -24,8 +24,8 @@
|
||||
namespace ripple {
|
||||
namespace RPC {
|
||||
|
||||
Output chunkedYieldingOutput (
|
||||
Output const& output, Yield const& yield, std::size_t chunkSize)
|
||||
Json::Output chunkedYieldingOutput (
|
||||
Json::Output const& output, Yield const& yield, std::size_t chunkSize)
|
||||
{
|
||||
auto count = std::make_shared <std::size_t> (0);
|
||||
return [chunkSize, count, output, yield] (boost::string_ref const& bytes)
|
||||
|
||||
Reference in New Issue
Block a user