Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions sdk/core/azure-core-amqp/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
### Features Added

- The Rust AMQP backend now generates SAS tokens from a shared access key. It sends CBS put-token requests with the `servicebus.windows.net:sastoken` token type.
- Added support for the AMQP Decimal types (AmqpDecimal128, AmqpDecimal64, and AmqpDecimal32).

### Breaking Changes

Expand Down
243 changes: 239 additions & 4 deletions sdk/core/azure-core-amqp/inc/azure/core/amqp/models/amqp_value.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,17 @@
#include <azure/core/internal/unique_handle.hpp>
#include <azure/core/uuid.hpp>

#include <algorithm>
#include <array>
#include <chrono>
#include <cstddef>
#include <cstdint>
#include <exception>
#include <functional>
#include <initializer_list>
#include <list>
#include <map>
#include <stdexcept>
#include <string>
#include <vector>

Expand Down Expand Up @@ -62,6 +65,9 @@ namespace Azure { namespace Core { namespace Amqp { namespace Models {
Long,
Float,
Double,
Decimal32,
Decimal64,
Decimal128,
Char,
Timestamp,
Uuid,
Expand Down Expand Up @@ -96,6 +102,188 @@ namespace Azure { namespace Core { namespace Amqp { namespace Models {
class AmqpComposite;
class AmqpDescribed;

/** @brief Provides storage and operations for a fixed-width AMQP decimal value.
*
* @tparam N The number of bytes in the encoded decimal value.
*/
template <std::size_t N> class AmqpDecimalBase {
std::array<std::uint8_t, N> data;

public:
/** @brief Constructs a decimal value initialized to zero. */
AmqpDecimalBase() = default;

/** @brief Destructs the decimal value. */
~AmqpDecimalBase() = default;

/** @brief Constructs a decimal value from its encoded bytes.
*
* @param value The encoded decimal value.
*/
explicit AmqpDecimalBase(std::array<std::uint8_t, N> const& value) : data(value) {}

/** @brief Constructs a decimal value from its encoded bytes.
*
* @param value The decimal encoding, which must contain exactly N bytes.
* @throws std::invalid_argument If @p value does not contain exactly N bytes.
*/
explicit AmqpDecimalBase(std::initializer_list<std::uint8_t> value)
{
if (value.size() != data.size())
{
throw std::invalid_argument("An AMQP decimal value must contain exactly N bytes.");
}
std::copy(value.begin(), value.end(), data.begin());
}

/** @brief Gets the encoded bytes.
*
* @returns A reference to the N-byte decimal encoding.
*/
std::array<std::uint8_t, N> const& AsArray() const { return data; }

/** @brief Compares two decimal values.
*
* @param that The value to compare against.
* @returns `true` if this value is less than @p that; otherwise, `false`.
*/
bool operator<(AmqpDecimalBase<N> const& that) const { return data < that.data; }

/** @brief Compares two decimal values for equality.
*
* @param that The value to compare against.
* @returns `true` if the encoded bytes are equal; otherwise, `false`.
*/
bool operator==(AmqpDecimalBase<N> const& that) const { return data == that.data; }

/** @brief Compares two decimal values for inequality.
*
* @param that The value to compare against.
* @returns `true` if the encoded bytes are not equal; otherwise, `false`.
*/
bool operator!=(AmqpDecimalBase<N> const& that) const { return data != that.data; }

/** @brief Compares two decimal values.
*
* @param that The value to compare against.
* @returns `true` if this value is greater than @p that; otherwise, `false`.
*/
bool operator>(AmqpDecimalBase<N> const& that) const { return data > that.data; }

/** @brief Compares two decimal values.
*
* @param that The value to compare against.
* @returns `true` if this value is less than or equal to @p that; otherwise, `false`.
*/
bool operator<=(AmqpDecimalBase<N> const& that) const { return data <= that.data; }

/** @brief Compares two decimal values.
*
* @param that The value to compare against.
* @returns `true` if this value is greater than or equal to @p that; otherwise, `false`.
*/
bool operator>=(AmqpDecimalBase<N> const& that) const { return data >= that.data; }

/** @brief Converts this value to its encoded byte array.
*
* @returns The N-byte decimal encoding.
*/
operator std::array<std::uint8_t, N>() const { return data; }

/** @brief Accesses an encoded byte.
*
* @param index The zero-based byte index.
* @returns A reference to the byte at @p index.
*/
std::uint8_t& operator[](std::size_t index) { return data[index]; }

/** @brief Accesses an encoded byte.
*
* @param index The zero-based byte index.
* @returns The byte at @p index.
*/
std::uint8_t operator[](std::size_t index) const { return data[index]; }
};

/** @brief Represents an AMQP decimal128 value.
*
* The value contains the 16-byte IEEE 754-2008 decimal128 encoding defined by AMQP.
*
* @see https://docs.oasis-open.org/amqp/core/v1.0/os/amqp-core-types-v1.0-os.html#type-decimal128
*/
class AmqpDecimal128 final : public AmqpDecimalBase<16> {
public:
/** @brief Constructs a decimal128 value initialized to zero. */
AmqpDecimal128() = default;

/** @brief Constructs a decimal128 value from its encoded bytes.
*
* @param value The 16-byte decimal128 encoding.
*/
explicit AmqpDecimal128(std::array<std::uint8_t, 16> const& value) : AmqpDecimalBase<16>(value)
{
}

/** @brief Constructs a decimal128 value from its encoded bytes.
*
* @param value The decimal128 encoding, which must contain exactly 16 bytes.
* @throws std::invalid_argument If @p value does not contain exactly 16 bytes.
*/
explicit AmqpDecimal128(std::initializer_list<std::uint8_t> value) : AmqpDecimalBase<16>(value)
{
}
};

/** @brief Represents an AMQP decimal64 value.
*
* The value contains the 8-byte IEEE 754-2008 decimal64 encoding defined by AMQP.
*
* @see https://docs.oasis-open.org/amqp/core/v1.0/os/amqp-core-types-v1.0-os.html#type-decimal64
*/
class AmqpDecimal64 final : public AmqpDecimalBase<8> {
public:
/** @brief Constructs a decimal64 value initialized to zero. */
AmqpDecimal64() = default;

/** @brief Constructs a decimal64 value from its encoded bytes.
*
* @param value The 8-byte decimal64 encoding.
*/
explicit AmqpDecimal64(std::array<std::uint8_t, 8> const& value) : AmqpDecimalBase<8>(value) {}

/** @brief Constructs a decimal64 value from its encoded bytes.
*
* @param value The decimal64 encoding, which must contain exactly 8 bytes.
* @throws std::invalid_argument If @p value does not contain exactly 8 bytes.
*/
explicit AmqpDecimal64(std::initializer_list<std::uint8_t> value) : AmqpDecimalBase<8>(value) {}
};

/** @brief Represents an AMQP decimal32 value.
*
* The value contains the 4-byte IEEE 754-2008 decimal32 encoding defined by AMQP.
*
* @see https://docs.oasis-open.org/amqp/core/v1.0/os/amqp-core-types-v1.0-os.html#type-decimal32
*/
class AmqpDecimal32 final : public AmqpDecimalBase<4> {
public:
/** @brief Constructs a decimal32 value initialized to zero. */
AmqpDecimal32() = default;

/** @brief Constructs a decimal32 value from its encoded bytes.
*
* @param value The 4-byte decimal32 encoding.
*/
explicit AmqpDecimal32(std::array<std::uint8_t, 4> const& value) : AmqpDecimalBase<4>(value) {}

/** @brief Constructs a decimal32 value from its encoded bytes.
*
* @param value The decimal32 encoding, which must contain exactly 4 bytes.
* @throws std::invalid_argument If @p value does not contain exactly 4 bytes.
*/
explicit AmqpDecimal32(std::initializer_list<std::uint8_t> value) : AmqpDecimalBase<4>(value) {}
};

/** An AMQP value.
* @details An AMQP value is a polymorphic type that can be used to represent any AMQP type.
*
Expand Down Expand Up @@ -258,6 +446,34 @@ namespace Azure { namespace Core { namespace Amqp { namespace Models {
*/
AmqpValue(double value);

/** @brief Construct an AMQP Decimal128 value.
*
* Defined in [AMQP Core Types
* section 1.6.20](http://docs.oasis-open.org/amqp/core/v1.0/os/amqp-core-types-v1.0-os.html#type-decimal128).
*
* @param value to be set.
*
*/
AmqpValue(AmqpDecimal128 const& value);
/** @brief Construct an AMQP Decimal64 value.
*
* Defined in [AMQP Core Types
* section 1.6.20](http://docs.oasis-open.org/amqp/core/v1.0/os/amqp-core-types-v1.0-os.html#type-decimal64).
*
* @param value to be set.
*
*/
AmqpValue(AmqpDecimal64 const& value);
/** @brief Construct an AMQP Decimal32 value.
*
* Defined in [AMQP Core Types
* section 1.6.20](http://docs.oasis-open.org/amqp/core/v1.0/os/amqp-core-types-v1.0-os.html#type-decimal32).
*
* @param value to be set.
*
*/
AmqpValue(AmqpDecimal32 const& value);

/** @brief Construct an AMQP string value, a UTF-8 encoded sequence of characters.
*
* Defined in [AMQP Core Types
Expand Down Expand Up @@ -302,10 +518,6 @@ namespace Azure { namespace Core { namespace Amqp { namespace Models {
*/
AmqpValue(char32_t value);

/** TODO:
* Decimal32, Decimal64, and Decimal128.
*/

/** @brief Construct an AMQP Uuid value, an RFC-4122 Universally Unique Identifier.
*
* Defined in [AMQP Core Types
Expand Down Expand Up @@ -447,6 +659,29 @@ namespace Azure { namespace Core { namespace Amqp { namespace Models {
*/
operator double() const;

/** @brief convert the current AMQP Value to an AmqpDecimal128 value.
*
* @returns the value as an AmqpDecimal128.
*
* @throws std::runtime_error if the underlying AMQP value is not an AmqpDecimal128.
*/
operator AmqpDecimal128() const;
/** @brief convert the current AMQP Value to an AmqpDecimal64 value.
*
* @returns the value as an AmqpDecimal64.
*
* @throws std::runtime_error if the underlying AMQP value is not an AmqpDecimal64.
*/
operator AmqpDecimal64() const;

/** @brief convert the current AMQP Value to an AmqpDecimal32 value.
*
* @returns the value as an AmqpDecimal32.
*
* @throws std::runtime_error if the underlying AMQP value is not an AmqpDecimal32.
*/
operator AmqpDecimal32() const;

/** @brief convert the current AMQP Value to a 32bit UCS32 value.
*
* @returns the value as a 32 bit character.
Expand Down
Loading
Loading