Skip to content

hrkn/picorison

Repository files navigation

PicoRISON - a C++ RISON parser / serializer

Copyright © 2009-2010 Cybozu Labs, Inc.
Copyright © 2011-2015 Kazuho Oku
Copyright © 2020 Haruki Nakayama

Licensed under 2-clause BSD license

Version

0.1.0-dev Build Status

Introduction

PicoRISON (forked from PicoJSON) is a tiny RISON parser / serializer for C++ with following properties:

  • header-file only
  • no external dependencies (only uses standard C++ libraries)
  • STL-frendly (arrays are represented by using std::vector, objects are std::map)
  • provides both pull interface and streaming (event-based) interface

What's RISON

RISON is structured data representation which is aimed to URL friendly for query string value without any percent encoding. The structure is almost fully convertible to JSON.

It's mostly familiar with Kibana interface URLs' query string.

You can try out conversion between JSON at Rison Playground.

Reading RISON using the pull interface

There are several ways to use the pull (DOM-like) interface of picorison.

The easiest way is to use the two-argument parse function.

std::string rison = "!('hello RISON')";
picorison::value v;
std::string err = picorizon::parse(v, rison);
if (! err.empty()) {
  std:cerr << err << std::endl;
}

Four-argument parse function accepts a pair of iterators, and returns the end position of the input.

const char* rison = "('a':1)";
picorison::value v;
std::string err;
const char* rison_end = picorison::parse(v, rison, rison + strlen(rison), &err);
if (! err.empty()) {
  std::cerr << err << std::endl;
}
std::istream_iterator input(std::cin);
picorison::value v;
std::string err;
input = picorison::parse(v, input, std::istream_iterator(), &err);
if (! err.empty()) {
  std::cerr << err << std::endl;
}

It is also possible to use the >> operator to parse the input, however this interface is not thread-safe.

picorison::value v;
std::cin >> v;
std::string err = picorison::get_last_error();

Accessing the values

Values of a RISON object is represented as instances of picorison::value class.

namespace picorison {

  class value {
    ...

  public:

    typedef std::vector<value> array;
    typedef std::map<std::string, value> object;

    value();                               // create a null object
    explicit value(bool b);                // create a boolean object
    explicit value(double n);              // create a number object
    explicit value(const std::string& s);  // create a string object
    explicit value(const array& a);        // create an array object
    explicit value(const object& o);       // create an "object"

    bool is<picorison::null>() const;       // check if the object is "null"

    bool is<bool>() const;                 // check if the object is a boolean
    const bool& get<bool>() const;         // const accessor (usable only if the object is a boolean)
    bool& get<bool>();                     // non-const accessor (usable only if the object is a boolean)

    bool is<double>() const;               // check if the object is a number
    const double& get<double>() const;     // const accessor (usable only if the object is a number)
    double& get<double>();                 // non-const accessor (usable only if the object is a number)

    bool is<std::string>() const;          // check if the object is a string
    const std::string& get<std::string>() const;
                                           // const accessor (usable only if the object is a string)
    std::string& get<std::string>();       // non-const accessor (usable only if the object is a string)

    bool is<array>() const;                // check if the object is an array
    const array& get<array>() const;       // const accessor (usable only if the object is an array)
    array& get<array>();                   // non-const accessor (usable only if the object is an array)

    bool is<object>() const;               // check if the object is an "object"
    const object& get<object>() const;     // const accessor (usable only if the object is an object)
    object& get<object>();                 // non-const accessor (usable only if the object is an array)

    bool evaluate_as_boolean() const;      // evaluates the object as a boolean

    std::string serialize() const;         // returns the object in RISON representation
    template void serialize(Iter os) const;
                                           // serializes the object in RISON representation through an output iterator

    std::string to_str() const;            // returns the object in string (for casual use)
  };
}

The code below parses a RISON string and prints the contents of the object.

picorison::value v;

// parse the input
std::cin >> v;
std::string err = picorison::get_last_error();
if (! err.empty()) {
  std::cerr << err << std::endl;
  exit(1);
}

// check if the type of the value is "object"
if (! v.is<picorison::object>()) {
  std::cerr << "RISON is not an object" << std::endl;
  exit(2);
}

// obtain a const reference to the map, and print the contents
const picorison::value::object& obj = v.get<picorison::object>();
for (picorison::value::object::const_iterator i = obj.begin();
     i != obj.end();
     ++i) {
  std::cout << i->first << ': ' << i->second.to_str() << std::endl;
}

Please note that the type check is mandatory; do not forget to check the type of the object by calling is<type>() before accessing the value by calling get<type>().

Reading RISON using the streaming (event-driven) interface

Please refer to the implementation of picorison::default_parse_context and picorison::null_parse_context. There is also an example (examples/streaming.cc) .

Serializing to RISON

Instances of the picorison::value class can be serialized in three ways, to ostream, to std::string, or to an output iterator.

picorison::value v;
...
std::cout << v;
picorison::value v;
...
std::string rison = v.serialize();
picorison::value v;
...
v.serialize(std::ostream_iterator<char>(std::cout));

Experimental support for int64_t

Experimental suport for int64_t becomes available if the code is compiled with preprocessor macro PICORISON_USE_INT64.

Turning on the feature will cause following changes to picorison:

  • new constructor picorison::value(int64_t) is defined
  • is<int64_t>() and get<int64_t>() become available
  • numerics in RISON within the bounds of int64_t and not using . nor e/E are considered as int64 type
  • the values are also avaliable as doubles as well (i.e. all values which are .is<int64_t>() == true are also .is<double>() == true)
  • int64 values are converted to double once get<double>() is called

Enabling the feature should not cause compatibility problem with code that do not use the feature.

Further reading

Examples can be found in the examples directory, and on the Wiki. Please add your favorite examples to the Wiki.

About

a header-file-only, RISON parser serializer in C++

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Contributors 24