blob: d1c39f07396e618a2aa98d7b8027bfc0bea2e1ba [file] [log] [blame]
Eric Newberry261dbc22015-07-22 23:18:18 -07001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
Teng Liang02960742017-10-24 00:36:45 -07002/*
Teng Liang5b323d12018-01-31 18:50:45 -07003 * Copyright (c) 2013-2018 Regents of the University of California.
Eric Newberry261dbc22015-07-22 23:18:18 -07004 *
5 * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
6 *
7 * ndn-cxx library is free software: you can redistribute it and/or modify it under the
8 * terms of the GNU Lesser General Public License as published by the Free Software
9 * Foundation, either version 3 of the License, or (at your option) any later version.
10 *
11 * ndn-cxx library is distributed in the hope that it will be useful, but WITHOUT ANY
12 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
13 * PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
14 *
15 * You should have received copies of the GNU General Public License and GNU Lesser
16 * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see
17 * <http://www.gnu.org/licenses/>.
18 *
19 * See AUTHORS.md for complete list of ndn-cxx authors and contributors.
20 */
21
Alexander Afanasyeve3874232017-03-26 16:58:59 -050022#ifndef NDN_CXX_LP_FIELD_DECL_HPP
23#define NDN_CXX_LP_FIELD_DECL_HPP
Eric Newberry261dbc22015-07-22 23:18:18 -070024
Teng Liang02960742017-10-24 00:36:45 -070025#include "empty-value.hpp"
Alexander Afanasyeve3874232017-03-26 16:58:59 -050026#include "field.hpp"
Junxiao Shi974b81a2018-04-21 01:37:03 +000027#include "sequence.hpp"
Alexander Afanasyeve3874232017-03-26 16:58:59 -050028#include "tlv.hpp"
Alexander Afanasyeve3874232017-03-26 16:58:59 -050029#include "../encoding/block-helpers.hpp"
30#include "../util/concepts.hpp"
Davide Pesavento14883ad2018-07-14 16:31:39 -040031
Eric Newberry261dbc22015-07-22 23:18:18 -070032#include <boost/concept/requires.hpp>
Davide Pesavento14883ad2018-07-14 16:31:39 -040033#include <boost/endian/conversion.hpp>
Eric Newberry261dbc22015-07-22 23:18:18 -070034
35namespace ndn {
36namespace lp {
Eric Newberry261dbc22015-07-22 23:18:18 -070037
Junxiao Shi974b81a2018-04-21 01:37:03 +000038/** \brief Indicate a uint64_t field shall be decoded and encoded as a non-negative integer.
39 */
40struct NonNegativeIntegerTag;
41
Eric Newberry261dbc22015-07-22 23:18:18 -070042template<typename TlvType, typename T>
43struct DecodeHelper
44{
45 static
46 BOOST_CONCEPT_REQUIRES(((WireDecodable<T>)), (T))
47 decode(const Block& wire)
48 {
Eric Newberry261dbc22015-07-22 23:18:18 -070049 T type;
50 type.wireDecode(wire);
51 return type;
52 }
53};
54
55template<typename TlvType>
Teng Liang02960742017-10-24 00:36:45 -070056struct DecodeHelper<TlvType, EmptyValue>
57{
58 static EmptyValue
59 decode(const Block& wire)
60 {
61 if (wire.value_size() != 0) {
62 BOOST_THROW_EXCEPTION(ndn::tlv::Error("NDNLP field of TLV-TYPE " + to_string(wire.type()) +
Junxiao Shi974b81a2018-04-21 01:37:03 +000063 " must be empty"));
Teng Liang02960742017-10-24 00:36:45 -070064 }
65
66 return EmptyValue{};
67 }
68};
69
70template<typename TlvType>
Junxiao Shi974b81a2018-04-21 01:37:03 +000071struct DecodeHelper<TlvType, NonNegativeIntegerTag>
72{
73 static uint64_t
74 decode(const Block& wire)
75 {
76 return readNonNegativeInteger(wire);
77 }
78};
79
80template<typename TlvType>
Eric Newberry261dbc22015-07-22 23:18:18 -070081struct DecodeHelper<TlvType, uint64_t>
82{
83 static uint64_t
84 decode(const Block& wire)
85 {
Junxiao Shi974b81a2018-04-21 01:37:03 +000086 // NDNLPv2 spec defines sequence number fields to be encoded as a fixed-width unsigned integer,
87 // but previous versions of ndn-cxx encode it as a NonNegativeInteger, so we decode it as such
88 // for backwards compatibility. In a future version, the decoder will be changed to accept
89 // 8-byte big endian only, to allow faster decoding.
Eric Newberry261dbc22015-07-22 23:18:18 -070090 return readNonNegativeInteger(wire);
91 }
92};
93
94template<typename TlvType>
95struct DecodeHelper<TlvType, std::pair<Buffer::const_iterator, Buffer::const_iterator>>
96{
97 static std::pair<Buffer::const_iterator, Buffer::const_iterator>
98 decode(const Block& wire)
99 {
Eric Newberry261dbc22015-07-22 23:18:18 -0700100 if (wire.value_size() == 0) {
Teng Liang02960742017-10-24 00:36:45 -0700101 BOOST_THROW_EXCEPTION(ndn::tlv::Error("NDNLP field of TLV-TYPE " + to_string(wire.type()) +
Junxiao Shi974b81a2018-04-21 01:37:03 +0000102 " cannot be empty"));
Eric Newberry261dbc22015-07-22 23:18:18 -0700103 }
104
105 return std::make_pair(wire.value_begin(), wire.value_end());
106 }
107};
108
109template<typename encoding::Tag TAG, typename TlvType, typename T>
110struct EncodeHelper
111{
112 static
Teng Liang5b323d12018-01-31 18:50:45 -0700113 BOOST_CONCEPT_REQUIRES(((WireEncodableWithEncodingBuffer<T>)), (size_t))
Eric Newberry261dbc22015-07-22 23:18:18 -0700114 encode(EncodingImpl<TAG>& encoder, const T& value)
115 {
116 return value.wireEncode(encoder);
117 }
118};
119
120template<typename encoding::Tag TAG, typename TlvType>
Teng Liang02960742017-10-24 00:36:45 -0700121struct EncodeHelper<TAG, TlvType, EmptyValue>
122{
123 static size_t
124 encode(EncodingImpl<TAG>& encoder, const EmptyValue value)
125 {
126 size_t length = 0;
127 length += encoder.prependVarNumber(0);
128 length += encoder.prependVarNumber(TlvType::value);
129 return length;
130 }
131};
132
133template<typename encoding::Tag TAG, typename TlvType>
Junxiao Shi974b81a2018-04-21 01:37:03 +0000134struct EncodeHelper<TAG, TlvType, NonNegativeIntegerTag>
135{
136 static size_t
137 encode(EncodingImpl<TAG>& encoder, uint64_t value)
138 {
139 return prependNonNegativeIntegerBlock(encoder, TlvType::value, value);
140 }
141};
142
143template<typename encoding::Tag TAG, typename TlvType>
Eric Newberry261dbc22015-07-22 23:18:18 -0700144struct EncodeHelper<TAG, TlvType, uint64_t>
145{
146 static size_t
Junxiao Shi974b81a2018-04-21 01:37:03 +0000147 encode(EncodingImpl<TAG>& encoder, uint64_t value)
Eric Newberry261dbc22015-07-22 23:18:18 -0700148 {
Davide Pesavento14883ad2018-07-14 16:31:39 -0400149 boost::endian::native_to_big_inplace(value);
150 return encoder.prependByteArrayBlock(TlvType::value,
151 reinterpret_cast<const uint8_t*>(&value), sizeof(value));
Eric Newberry261dbc22015-07-22 23:18:18 -0700152 }
153};
154
155template<typename encoding::Tag TAG, typename TlvType>
156struct EncodeHelper<TAG, TlvType, std::pair<Buffer::const_iterator, Buffer::const_iterator>>
157{
158 static size_t
159 encode(EncodingImpl<TAG>& encoder, const std::pair<Buffer::const_iterator, Buffer::const_iterator>& value)
160 {
161 size_t length = 0;
162 length += encoder.prependRange(value.first, value.second);
163 length += encoder.prependVarNumber(length);
164 length += encoder.prependVarNumber(TlvType::value);
165 return length;
166 }
167};
168
Junxiao Shi974b81a2018-04-21 01:37:03 +0000169/** \brief Declare a field.
170 * \tparam LOCATION a tag that indicates where the field is in an LpPacket.
171 * \tparam VALUE type of field value.
172 * \tparam TYPE TLV-TYPE number of the field.
173 * \tparam REPEATABLE whether the field is repeatable.
174 * \tparam DECODER_TAG selects a specialization of DecodeHelper.
175 * \tparam ENCODER_TAG selects a specialization of EncodeHelper.
176 */
177template<typename LOCATION, typename VALUE, uint64_t TYPE, bool REPEATABLE = false,
178 typename DECODER_TAG = VALUE, typename ENCODER_TAG = VALUE>
Eric Newberry261dbc22015-07-22 23:18:18 -0700179class FieldDecl
180{
181public:
182 typedef LOCATION FieldLocation;
183 typedef VALUE ValueType;
184 typedef std::integral_constant<uint64_t, TYPE> TlvType;
185 typedef std::integral_constant<bool, REPEATABLE> IsRepeatable;
186
Junxiao Shi974b81a2018-04-21 01:37:03 +0000187 /** \brief Decode a field.
188 * \param wire an element with top-level TLV-TYPE \c TlvType::value.
189 * \return value of the field.
190 * \throw ndn::tlv::Error decode failure.
Eric Newberry83872fd2015-08-06 17:01:24 -0700191 */
Eric Newberry261dbc22015-07-22 23:18:18 -0700192 static ValueType
193 decode(const Block& wire)
194 {
Eric Newberry83872fd2015-08-06 17:01:24 -0700195 if (wire.type() != TlvType::value) {
Junxiao Shi974b81a2018-04-21 01:37:03 +0000196 BOOST_THROW_EXCEPTION(ndn::tlv::Error("Unexpected TLV-TYPE " + to_string(wire.type())));
Eric Newberry83872fd2015-08-06 17:01:24 -0700197 }
198
Junxiao Shi974b81a2018-04-21 01:37:03 +0000199 return DecodeHelper<TlvType, DECODER_TAG>::decode(wire);
Eric Newberry261dbc22015-07-22 23:18:18 -0700200 }
201
Junxiao Shi974b81a2018-04-21 01:37:03 +0000202 /** \brief Encode a field and prepend to \p encoder.
203 * \param encoder a buffer encoder or estimator.
204 * \param value value of the field.
Eric Newberry83872fd2015-08-06 17:01:24 -0700205 */
Junxiao Shi974b81a2018-04-21 01:37:03 +0000206 template<typename encoding::Tag TAG>
Eric Newberry261dbc22015-07-22 23:18:18 -0700207 static size_t
Junxiao Shi974b81a2018-04-21 01:37:03 +0000208 encode(EncodingImpl<TAG>& encoder, const ValueType& value)
Eric Newberry261dbc22015-07-22 23:18:18 -0700209 {
Junxiao Shi974b81a2018-04-21 01:37:03 +0000210 return EncodeHelper<TAG, TlvType, ENCODER_TAG>::encode(encoder, value);
Eric Newberry261dbc22015-07-22 23:18:18 -0700211 }
212};
213
Eric Newberry261dbc22015-07-22 23:18:18 -0700214} // namespace lp
Junxiao Shi09bcab52016-07-18 02:43:34 +0000215} // namespace ndn
Eric Newberry261dbc22015-07-22 23:18:18 -0700216
Alexander Afanasyeve3874232017-03-26 16:58:59 -0500217#endif // NDN_CXX_LP_FIELD_DECL_HPP