| /* |
| * 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/codec/encoder.hpp" |
| |
| #include "proton_bits.hpp" |
| #include "types_internal.hpp" |
| #include "msg.hpp" |
| |
| #include "proton/annotation_key.hpp" |
| #include "proton/binary.hpp" |
| #include "proton/decimal.hpp" |
| #include "proton/message_id.hpp" |
| #include "proton/null.hpp" |
| #include "proton/scalar_base.hpp" |
| #include "proton/symbol.hpp" |
| #include "proton/timestamp.hpp" |
| #include "proton/value.hpp" |
| |
| #include <proton/codec.h> |
| |
| #include <algorithm> |
| #include <assert.h> |
| |
| namespace proton { |
| namespace codec { |
| |
| void encoder::check(long result) { |
| if (result < 0) |
| throw conversion_error(error_str(pn_data_error(pn_object()), result)); |
| } |
| |
| |
| encoder::encoder(internal::value_base& v) : data(v.data()) { |
| clear(); |
| } |
| |
| bool encoder::encode(char* buffer, size_t& size) { |
| internal::state_guard sg(*this); // In case of error |
| ssize_t result = pn_data_encode(pn_object(), buffer, size); |
| if (result == PN_OVERFLOW) { |
| result = pn_data_encoded_size(pn_object()); |
| if (result >= 0) { |
| size = size_t(result); |
| return false; |
| } |
| } |
| check(result); |
| size = size_t(result); |
| sg.cancel(); // Don't restore state, all is well. |
| pn_data_clear(pn_object()); |
| return true; |
| } |
| |
| void encoder::encode(std::string& s) { |
| s.resize(std::max(s.capacity(), size_t(1))); // Use full capacity, ensure not empty |
| size_t size = s.size(); |
| assert(!s.empty()); |
| if (!encode(&s[0], size)) { |
| s.resize(size); |
| assert(!s.empty()); |
| encode(&s[0], size); |
| } |
| } |
| |
| std::string encoder::encode() { |
| std::string s; |
| encode(s); |
| return s; |
| } |
| |
| encoder& encoder::operator<<(const start& s) { |
| switch (s.type) { |
| case ARRAY: pn_data_put_array(pn_object(), s.is_described, pn_type_t(s.element)); break; |
| case MAP: pn_data_put_map(pn_object()); break; |
| case LIST: pn_data_put_list(pn_object()); break; |
| case DESCRIBED: pn_data_put_described(pn_object()); break; |
| default: |
| throw conversion_error(MSG("" << s.type << " is not a container type")); |
| } |
| pn_data_enter(pn_object()); |
| return *this; |
| } |
| |
| encoder& encoder::operator<<(const finish&) { |
| pn_data_exit(pn_object()); |
| return *this; |
| } |
| |
| namespace { |
| |
| template <class T, class U> T coerce(const U &x) { return x; } |
| template <> pn_uuid_t coerce(const uuid& x) { pn_uuid_t y; byte_copy(y, x); return y; } |
| template <> pn_decimal32_t coerce(const decimal32 &x) { pn_decimal32_t y; byte_copy(y, x); return y; } |
| template <> pn_decimal64_t coerce(const decimal64 &x) { pn_decimal64_t y; byte_copy(y, x); return y; } |
| template <> pn_decimal128_t coerce(const decimal128 &x) { pn_decimal128_t y; byte_copy(y, x); return y; } |
| |
| int pn_data_put_amqp_string(pn_data_t *d, const std::string& x) { return pn_data_put_string(d, pn_bytes(x)); } |
| int pn_data_put_amqp_binary(pn_data_t *d, const binary& x) { return pn_data_put_binary(d, pn_bytes(x)); } |
| int pn_data_put_amqp_symbol(pn_data_t *d, const symbol& x) { return pn_data_put_symbol(d, pn_bytes(x)); } |
| } // namespace |
| |
| template <class T, class U> |
| encoder& encoder::insert(const T& x, int (*put)(pn_data_t*, U)) { |
| internal::state_guard sg(*this); // Save state in case of error. |
| check(put(pn_object(), coerce<U>(x))); |
| sg.cancel(); // Don't restore state, all is good. |
| return *this; |
| } |
| |
| encoder& encoder::operator<<(bool x) { return insert(x, pn_data_put_bool); } |
| encoder& encoder::operator<<(uint8_t x) { return insert(x, pn_data_put_ubyte); } |
| encoder& encoder::operator<<(int8_t x) { return insert(x, pn_data_put_byte); } |
| encoder& encoder::operator<<(uint16_t x) { return insert(x, pn_data_put_ushort); } |
| encoder& encoder::operator<<(int16_t x) { return insert(x, pn_data_put_short); } |
| encoder& encoder::operator<<(uint32_t x) { return insert(x, pn_data_put_uint); } |
| encoder& encoder::operator<<(int32_t x) { return insert(x, pn_data_put_int); } |
| encoder& encoder::operator<<(wchar_t x) { return insert(x, pn_data_put_char); } |
| encoder& encoder::operator<<(uint64_t x) { return insert(x, pn_data_put_ulong); } |
| encoder& encoder::operator<<(int64_t x) { return insert(x, pn_data_put_long); } |
| encoder& encoder::operator<<(timestamp x) { return insert(x.milliseconds(), pn_data_put_timestamp); } |
| encoder& encoder::operator<<(float x) { return insert(x, pn_data_put_float); } |
| encoder& encoder::operator<<(double x) { return insert(x, pn_data_put_double); } |
| encoder& encoder::operator<<(decimal32 x) { return insert(x, pn_data_put_decimal32); } |
| encoder& encoder::operator<<(decimal64 x) { return insert(x, pn_data_put_decimal64); } |
| encoder& encoder::operator<<(decimal128 x) { return insert(x, pn_data_put_decimal128); } |
| encoder& encoder::operator<<(const uuid& x) { return insert(x, pn_data_put_uuid); } |
| encoder& encoder::operator<<(const std::string& x) { return insert(x, pn_data_put_amqp_string); } |
| encoder& encoder::operator<<(const symbol& x) { return insert(x, pn_data_put_amqp_symbol); } |
| encoder& encoder::operator<<(const binary& x) { return insert(x, pn_data_put_amqp_binary); } |
| encoder& encoder::operator<<(const null&) { pn_data_put_null(pn_object()); return *this; } |
| #if PN_CPP_HAS_NULLPTR |
| encoder& encoder::operator<<(decltype(nullptr)) { pn_data_put_null(pn_object()); return *this; } |
| #endif |
| |
| encoder& encoder::operator<<(const scalar_base& x) { return insert(x.atom_, pn_data_put_atom); } |
| |
| encoder& encoder::operator<<(const internal::value_base& x) { |
| data d = x.data_; |
| if (*this == d) |
| throw conversion_error("cannot insert into self"); |
| if (!d || d.empty()) |
| return *this << null(); |
| d.rewind(); |
| check(append(d)); |
| return *this; |
| } |
| |
| } // codec |
| } // proton |