blob: 9c14ade7fc5c35ff91e1681f380dc219b47bd896 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
#include <proton/value.hpp>
#include <algorithm>
#include <iostream>
#include <iterator>
#include <map>
#include <sstream>
#include <vector>
#include <list>
// Examples of how to use the encoder and decoder to create and examine AMQP values.
//
// Print is defined at the end as an example of how to query and extract complex
// values from a decoder in terms of their simple components.
void print(proton::value&);
// Some helper templates to print map and std::vector results.
namespace std {
template<class T, class U> ostream& operator<<(ostream& o, const std::pair<T,U>& p) {
return o << p.first << ":" << p.second;
}
template<class T> ostream& operator<<(ostream& o, const std::vector<T>& v) {
o << "[ ";
ostream_iterator<T> oi(o, " ");
copy(v.begin(), v.end(), oi);
return o << "]";
}
template<class T> ostream& operator<<(ostream& o, const std::list<T>& v) {
o << "[ ";
ostream_iterator<T> oi(o, " ");
copy(v.begin(), v.end(), oi);
return o << "]";
}
template<class K, class T> ostream& operator<<(ostream& o, const map<K, T>& m) {
o << "{ ";
ostream_iterator<std::pair<K,T> > oi(o, " ");
copy(m.begin(), m.end(), oi);
return o << "}";
}
}
// Insert/extract native C++ containers with uniform type values.
void uniform_containers() {
std::cout << std::endl << "== Array, list and map of uniform type." << std::endl;
proton::value v;
std::vector<int> a;
a.push_back(1);
a.push_back(2);
a.push_back(3);
// By default a C++ container is encoded as an AMQP array.
v = a;
print(v);
std::list<int> a1;
v.get(a1); // Decode as a C++ std::list instead
std::cout << a1 << std::endl;
// You can specify that a container should be encoded as an AMQP list instead.
v = proton::as<proton::LIST>(a1);
print(v);
std::cout << v.get<std::vector<int> >() << std::endl;
// C++ map types (types with key_type, mapped_type) convert to an AMQP map by default.
std::map<std::string, int> m;
m["one"] = 1;
m["two"] = 2;
v = m;
print(v);
std::cout << v.get<std::map<std::string, int> >() << std::endl;
// You can convert a sequence of pairs to an AMQP map if you need to control the
// encoded ordering.
std::vector<std::pair<std::string, int> > pairs;
pairs.push_back(std::make_pair("z", 3));
pairs.push_back(std::make_pair("a", 4));
v = proton::as<proton::MAP>(pairs);
print(v);
// You can also decode an AMQP map as a sequence of pairs using decoder() and proton::to_pairs
std::vector<std::pair<std::string, int> > pairs2;
v.decode() >> proton::to_pairs(pairs2);
std::cout << pairs2 << std::endl;
}
// Containers with mixed types use value to represent arbitrary AMQP types.
void mixed_containers() {
std::cout << std::endl << "== List and map of mixed type values." << std::endl;
proton::value v;
std::vector<proton::value> l;
l.push_back(proton::value(42));
l.push_back(proton::value(proton::amqp_string("foo")));
// By default, a sequence of proton::value is treated as an AMQP list.
v = l;
print(v);
std::vector<proton::value> l2;
v.get(l2);
std::cout << l2 << std::endl;
std::map<proton::value, proton::value> m;
m[proton::value("five")] = proton::value(5);
m[proton::value(4)] = proton::value("four");
v = m;
print(v);
std::map<proton::value, proton::value> m2;
v.get(m2);
std::cout << m2 << std::endl;
}
// Insert using stream operators (see print_next for example of extracting with stream ops.)
void insert_stream_operators() {
std::cout << std::endl << "== Insert with stream operators." << std::endl;
proton::value v;
// Create an array of INT with values [1, 2, 3]
v.encode() << proton::start::array(proton::INT)
<< proton::amqp_int(1) << proton::amqp_int(2) << proton::amqp_int(3)
<< proton::finish();
print(v);
// Create a mixed-type list of the values [42, false, "x"].
v.encode() << proton::start::list()
<< proton::amqp_int(42) << false << proton::amqp_symbol("x")
<< proton::finish();
print(v);
// Create a map { "k1":42, "k2": false }
v.encode() << proton::start::map()
<< "k1" << proton::amqp_int(42)
<< proton::amqp_symbol("k2") << false
<< proton::finish();
print(v);
}
int main(int, char**) {
try {
uniform_containers();
mixed_containers();
insert_stream_operators();
return 0;
} catch (const std::exception& e) {
std::cerr << std::endl << "error: " << e.what() << std::endl;
}
return 1;
}
// print_next prints the next value from values by recursively descending into complex values.
//
// NOTE this is for example puroses only: There is a built in ostream operator<< for values.
//
//
void print_next(proton::decoder& d) {
proton::type_id type = d.type();
proton::start s;
switch (type) {
case proton::ARRAY: {
d >> s;
std::cout << "array<" << s.element;
if (s.is_described) {
std::cout << ", descriptor=";
print_next(d);
}
std::cout << ">[";
for (size_t i = 0; i < s.size; ++i) {
if (i) std::cout << ", ";
print_next(d);
}
std::cout << "]";
d >> proton::finish();
break;
}
case proton::LIST: {
d >> s;
std::cout << "list[";
for (size_t i = 0; i < s.size; ++i) {
if (i) std::cout << ", ";
print_next(d);
}
std::cout << "]";
d >> proton::finish();
break;
}
case proton::MAP: {
d >> s;
std::cout << "map{";
for (size_t i = 0; i < s.size/2; ++i) {
if (i) std::cout << ", ";
print_next(d);
std::cout << ":"; // key:value
print_next(d);
}
std::cout << "}";
d >> proton::finish();
break;
}
case proton::DESCRIBED: {
d >> s;
std::cout << "described(";
print_next(d); // Descriptor
print_next(d); // value
d >> proton::finish();
break;
}
default:
// A simple type. We could continue the switch for all AMQP types but
// we will take a short cut and extract to another value and print that.
proton::value v2;
d >> v2;
std::cout << type << "(" << v2 << ")";
}
}
// Print a value, for example purposes. Normal code can use operator<<
void print(proton::value& v) {
proton::decoder d = v.decode();
d.rewind();
while (d.more()) {
print_next(d);
if (d.more()) std::cout << ", ";
}
std::cout << std::endl;
}