blob: a9a543efb2d2fee819af636f01ade9f7037414a5 [file] [log] [blame]
// Copyright 2023 The Pigweed Authors
//
// Licensed 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
//
// https://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.
#pragma once
/// @file pw_protobuf/find.h
///
/// Sometimes, only a single field from a serialized message needs to be read.
/// In these cases, setting up a decoder and iterating through the message is a
/// lot of boilerplate. ``pw_protobuf`` provides convenient ``Find*()``
/// functions which handle this for you.
///
/// @note Each call to ``Find*()`` linearly scans through the message. If you
/// have to read multiple fields, it is more efficient to instantiate your own
/// decoder as described above.
///
/// @code{.cpp}
///
/// pw::Status PrintCustomerAge(pw::ConstByteSpan serialized_customer) {
/// pw::Result<uint32_t> age = pw::protobuf::FindUint32(
/// serialized_customer, Customer::Fields::kAge);
/// if (!age.ok()) {
/// return age.status();
/// }
///
/// PW_LOG_INFO("Customer's age is %u", *age);
/// return pw::OkStatus();
/// }
///
/// @endcode
#include "pw_bytes/span.h"
#include "pw_protobuf/decoder.h"
#include "pw_protobuf/stream_decoder.h"
#include "pw_result/result.h"
#include "pw_status/try.h"
#include "pw_string/string.h"
namespace pw::protobuf {
namespace internal {
Status AdvanceToField(Decoder& decoder, uint32_t field_number);
Status AdvanceToField(StreamDecoder& decoder, uint32_t field_number);
template <typename T, auto ReadFn>
Result<T> Find(ConstByteSpan message, uint32_t field_number) {
T output;
Decoder decoder(message);
PW_TRY(AdvanceToField(decoder, field_number));
PW_TRY((decoder.*ReadFn)(&output));
return output;
}
template <typename T, auto ReadFn>
Result<T> Find(stream::Reader& reader, uint32_t field_number) {
StreamDecoder decoder(reader);
PW_TRY(AdvanceToField(decoder, field_number));
Result<T> result = (decoder.*ReadFn)();
// The StreamDecoder returns a NOT_FOUND if trying to read the wrong type for
// a field. Remap this to FAILED_PRECONDITION for consistency with the
// non-stream Find.
return result.status().IsNotFound() ? Result<T>(Status::FailedPrecondition())
: result;
}
} // namespace internal
/// @brief Scans a serialized protobuf message for a `uint32` field.
///
/// @param message The serialized message to search.
/// @param field_number Protobuf field number of the field.
///
/// @returns @rst
///
/// .. pw-status-codes::
///
/// OK: Returns the field.
///
/// NOT_FOUND: The field is not present.
///
/// DATA_LOSS: The serialized message is not a valid protobuf.
///
/// FAILED_PRECONDITION: The field exists, but is not the correct type.
///
/// @endrst
inline Result<uint32_t> FindUint32(ConstByteSpan message,
uint32_t field_number) {
return internal::Find<uint32_t, &Decoder::ReadUint32>(message, field_number);
}
template <typename T, typename = std::enable_if_t<std::is_enum_v<T>>>
inline Result<uint32_t> FindUint32(ConstByteSpan message, T field) {
return FindUint32(message, static_cast<uint32_t>(field));
}
/// @brief Scans a serialized protobuf message for a `uint32` field.
///
/// @param message_stream The serialized message to search.
/// @param field_number Protobuf field number of the field.
///
/// @returns @rst
///
/// .. pw-status-codes::
///
/// OK: Returns the field.
///
/// NOT_FOUND: The field is not present.
///
/// DATA_LOSS: The serialized message is not a valid protobuf.
///
/// FAILED_PRECONDITION: The field exists, but is not the correct type.
///
/// @endrst
inline Result<uint32_t> FindUint32(stream::Reader& message_stream,
uint32_t field_number) {
return internal::Find<uint32_t, &StreamDecoder::ReadUint32>(message_stream,
field_number);
}
template <typename T, typename = std::enable_if_t<std::is_enum_v<T>>>
inline Result<uint32_t> FindUint32(stream::Reader& message_stream, T field) {
return FindUint32(message_stream, static_cast<uint32_t>(field));
}
/// @brief Scans a serialized protobuf message for an `int32` field.
///
/// @param message The serialized message to search.
/// @param field_number Protobuf field number of the field.
///
/// @returns @rst
///
/// .. pw-status-codes::
///
/// OK: Returns the field.
///
/// NOT_FOUND: The field is not present.
///
/// DATA_LOSS: The serialized message is not a valid protobuf.
///
/// FAILED_PRECONDITION: The field exists, but is not the correct type.
///
/// @endrst
inline Result<int32_t> FindInt32(ConstByteSpan message, uint32_t field_number) {
return internal::Find<int32_t, &Decoder::ReadInt32>(message, field_number);
}
template <typename T, typename = std::enable_if_t<std::is_enum_v<T>>>
inline Result<int32_t> FindInt32(ConstByteSpan message, T field) {
return FindInt32(message, static_cast<uint32_t>(field));
}
/// @brief Scans a serialized protobuf message for an `int32` field.
///
/// @param message_stream The serialized message to search.
/// @param field_number Protobuf field number of the field.
///
/// @returns @rst
///
/// .. pw-status-codes::
///
/// OK: Returns the field.
///
/// NOT_FOUND: The field is not present.
///
/// DATA_LOSS: The serialized message is not a valid protobuf.
///
/// FAILED_PRECONDITION: The field exists, but is not the correct type.
///
/// @endrst
inline Result<int32_t> FindInt32(stream::Reader& message_stream,
uint32_t field_number) {
return internal::Find<int32_t, &StreamDecoder::ReadInt32>(message_stream,
field_number);
}
template <typename T, typename = std::enable_if_t<std::is_enum_v<T>>>
inline Result<int32_t> FindInt32(stream::Reader& message_stream, T field) {
return FindInt32(message_stream, static_cast<uint32_t>(field));
}
/// @brief Scans a serialized protobuf message for an `sint32` field.
///
/// @param message The serialized message to search.
/// @param field_number Protobuf field number of the field.
///
/// @returns @rst
///
/// .. pw-status-codes::
///
/// OK: Returns the field.
///
/// NOT_FOUND: The field is not present.
///
/// DATA_LOSS: The serialized message is not a valid protobuf.
///
/// FAILED_PRECONDITION: The field exists, but is not the correct type.
///
/// @endrst
inline Result<int32_t> FindSint32(ConstByteSpan message,
uint32_t field_number) {
return internal::Find<int32_t, &Decoder::ReadSint32>(message, field_number);
}
template <typename T, typename = std::enable_if_t<std::is_enum_v<T>>>
inline Result<int32_t> FindSint32(ConstByteSpan message, T field) {
return FindSint32(message, static_cast<uint32_t>(field));
}
/// @brief Scans a serialized protobuf message for an `sint32` field.
///
/// @param message_stream The serialized message to search.
/// @param field_number Protobuf field number of the field.
///
/// @returns @rst
///
/// .. pw-status-codes::
///
/// OK: Returns the field.
///
/// NOT_FOUND: The field is not present.
///
/// DATA_LOSS: The serialized message is not a valid protobuf.
///
/// FAILED_PRECONDITION: The field exists, but is not the correct type.
///
/// @endrst
inline Result<int32_t> FindSint32(stream::Reader& message_stream,
uint32_t field_number) {
return internal::Find<int32_t, &StreamDecoder::ReadSint32>(message_stream,
field_number);
}
template <typename T, typename = std::enable_if_t<std::is_enum_v<T>>>
inline Result<int32_t> FindSint32(stream::Reader& message_stream, T field) {
return FindSint32(message_stream, static_cast<uint32_t>(field));
}
/// @brief Scans a serialized protobuf message for a `uint64` field.
///
/// @param message The serialized message to search.
/// @param field_number Protobuf field number of the field.
///
/// @returns @rst
///
/// .. pw-status-codes::
///
/// OK: Returns the field.
///
/// NOT_FOUND: The field is not present.
///
/// DATA_LOSS: The serialized message is not a valid protobuf.
///
/// FAILED_PRECONDITION: The field exists, but is not the correct type.
///
/// @endrst
inline Result<uint64_t> FindUint64(ConstByteSpan message,
uint32_t field_number) {
return internal::Find<uint64_t, &Decoder::ReadUint64>(message, field_number);
}
template <typename T, typename = std::enable_if_t<std::is_enum_v<T>>>
inline Result<uint64_t> FindUint64(ConstByteSpan message, T field) {
return FindUint64(message, static_cast<uint32_t>(field));
}
/// @brief Scans a serialized protobuf message for a `uint64` field.
///
/// @param message_stream The serialized message to search.
/// @param field_number Protobuf field number of the field.
///
/// @returns @rst
///
/// .. pw-status-codes::
///
/// OK: Returns the field.
///
/// NOT_FOUND: The field is not present.
///
/// DATA_LOSS: The serialized message is not a valid protobuf.
///
/// FAILED_PRECONDITION: The field exists, but is not the correct type.
///
/// @endrst
inline Result<uint64_t> FindUint64(stream::Reader& message_stream,
uint32_t field_number) {
return internal::Find<uint64_t, &StreamDecoder::ReadUint64>(message_stream,
field_number);
}
template <typename T, typename = std::enable_if_t<std::is_enum_v<T>>>
inline Result<uint64_t> FindUint64(stream::Reader& message_stream, T field) {
return FindUint64(message_stream, static_cast<uint32_t>(field));
}
/// @brief Scans a serialized protobuf message for an `int64` field.
///
/// @param message The serialized message to search.
/// @param field_number Protobuf field number of the field.
///
/// @returns @rst
///
/// .. pw-status-codes::
///
/// OK: Returns the field.
///
/// NOT_FOUND: The field is not present.
///
/// DATA_LOSS: The serialized message is not a valid protobuf.
///
/// FAILED_PRECONDITION: The field exists, but is not the correct type.
///
/// @endrst
inline Result<int64_t> FindInt64(ConstByteSpan message, uint32_t field_number) {
return internal::Find<int64_t, &Decoder::ReadInt64>(message, field_number);
}
template <typename T, typename = std::enable_if_t<std::is_enum_v<T>>>
inline Result<int64_t> FindInt64(ConstByteSpan message, T field) {
return FindInt64(message, static_cast<uint32_t>(field));
}
/// @brief Scans a serialized protobuf message for an `int64` field.
///
/// @param message_stream The serialized message to search.
/// @param field_number Protobuf field number of the field.
///
/// @returns @rst
///
/// .. pw-status-codes::
///
/// OK: Returns the field.
///
/// NOT_FOUND: The field is not present.
///
/// DATA_LOSS: The serialized message is not a valid protobuf.
///
/// FAILED_PRECONDITION: The field exists, but is not the correct type.
///
/// @endrst
inline Result<int64_t> FindInt64(stream::Reader& message_stream,
uint32_t field_number) {
return internal::Find<int64_t, &StreamDecoder::ReadInt64>(message_stream,
field_number);
}
template <typename T, typename = std::enable_if_t<std::is_enum_v<T>>>
inline Result<int64_t> FindInt64(stream::Reader& message_stream, T field) {
return FindInt64(message_stream, static_cast<uint32_t>(field));
}
/// @brief Scans a serialized protobuf message for an `sint64` field.
///
/// @param message The serialized message to search.
/// @param field_number Protobuf field number of the field.
///
/// @returns @rst
///
/// .. pw-status-codes::
///
/// OK: Returns the field.
///
/// NOT_FOUND: The field is not present.
///
/// DATA_LOSS: The serialized message is not a valid protobuf.
///
/// FAILED_PRECONDITION: The field exists, but is not the correct type.
///
/// @endrst
inline Result<int64_t> FindSint64(ConstByteSpan message,
uint32_t field_number) {
return internal::Find<int64_t, &Decoder::ReadSint64>(message, field_number);
}
template <typename T, typename = std::enable_if_t<std::is_enum_v<T>>>
inline Result<int64_t> FindSint64(ConstByteSpan message, T field) {
return FindSint64(message, static_cast<uint32_t>(field));
}
/// @brief Scans a serialized protobuf message for an `sint64` field.
///
/// @param message_stream The serialized message to search.
/// @param field_number Protobuf field number of the field.
///
/// @returns @rst
///
/// .. pw-status-codes::
///
/// OK: Returns the field.
///
/// NOT_FOUND: The field is not present.
///
/// DATA_LOSS: The serialized message is not a valid protobuf.
///
/// FAILED_PRECONDITION: The field exists, but is not the correct type.
///
/// @endrst
inline Result<int64_t> FindSint64(stream::Reader& message_stream,
uint32_t field_number) {
return internal::Find<int64_t, &StreamDecoder::ReadSint64>(message_stream,
field_number);
}
template <typename T, typename = std::enable_if_t<std::is_enum_v<T>>>
inline Result<int64_t> FindSint64(stream::Reader& message_stream, T field) {
return FindSint64(message_stream, static_cast<uint32_t>(field));
}
/// @brief Scans a serialized protobuf message for a `bool` field.
///
/// @param message The serialized message to search.
/// @param field_number Protobuf field number of the field.
///
/// @returns @rst
///
/// .. pw-status-codes::
///
/// OK: Returns the field.
///
/// NOT_FOUND: The field is not present.
///
/// DATA_LOSS: The serialized message is not a valid protobuf.
///
/// FAILED_PRECONDITION: The field exists, but is not the correct type.
///
/// @endrst
inline Result<bool> FindBool(ConstByteSpan message, uint32_t field_number) {
return internal::Find<bool, &Decoder::ReadBool>(message, field_number);
}
template <typename T, typename = std::enable_if_t<std::is_enum_v<T>>>
inline Result<bool> FindBool(ConstByteSpan message, T field) {
return FindBool(message, static_cast<uint32_t>(field));
}
/// @brief Scans a serialized protobuf message for a `bool` field.
///
/// @param message_stream The serialized message to search.
/// @param field_number Protobuf field number of the field.
///
/// @returns @rst
///
/// .. pw-status-codes::
///
/// OK: Returns the field.
///
/// NOT_FOUND: The field is not present.
///
/// DATA_LOSS: The serialized message is not a valid protobuf.
///
/// FAILED_PRECONDITION: The field exists, but is not the correct type.
///
/// @endrst
inline Result<bool> FindBool(stream::Reader& message_stream,
uint32_t field_number) {
return internal::Find<bool, &StreamDecoder::ReadBool>(message_stream,
field_number);
}
template <typename T, typename = std::enable_if_t<std::is_enum_v<T>>>
inline Result<bool> FindBool(stream::Reader& message_stream, T field) {
return FindBool(message_stream, static_cast<uint32_t>(field));
}
/// @brief Scans a serialized protobuf message for a `fixed32` field.
///
/// @param message The serialized message to search.
/// @param field_number Protobuf field number of the field.
///
/// @returns @rst
///
/// .. pw-status-codes::
///
/// OK: Returns the field.
///
/// NOT_FOUND: The field is not present.
///
/// DATA_LOSS: The serialized message is not a valid protobuf.
///
/// FAILED_PRECONDITION: The field exists, but is not the correct type.
///
/// @endrst
inline Result<uint32_t> FindFixed32(ConstByteSpan message,
uint32_t field_number) {
return internal::Find<uint32_t, &Decoder::ReadFixed32>(message, field_number);
}
template <typename T, typename = std::enable_if_t<std::is_enum_v<T>>>
inline Result<uint32_t> FindFixed32(ConstByteSpan message, T field) {
return FindFixed32(message, static_cast<uint32_t>(field));
}
/// @brief Scans a serialized protobuf message for a `fixed32` field.
///
/// @param message_stream The serialized message to search.
/// @param field_number Protobuf field number of the field.
///
/// @returns @rst
///
/// .. pw-status-codes::
///
/// OK: Returns the field.
///
/// NOT_FOUND: The field is not present.
///
/// DATA_LOSS: The serialized message is not a valid protobuf.
///
/// FAILED_PRECONDITION: The field exists, but is not the correct type.
///
/// @endrst
inline Result<uint32_t> FindFixed32(stream::Reader& message_stream,
uint32_t field_number) {
return internal::Find<uint32_t, &StreamDecoder::ReadFixed32>(message_stream,
field_number);
}
template <typename T, typename = std::enable_if_t<std::is_enum_v<T>>>
inline Result<uint32_t> FindFixed32(stream::Reader& message_stream, T field) {
return FindFixed32(message_stream, static_cast<uint32_t>(field));
}
/// @brief Scans a serialized protobuf message for a `fixed64` field.
///
/// @param message The serialized message to search.
/// @param field_number Protobuf field number of the field.
///
/// @returns @rst
///
/// .. pw-status-codes::
///
/// OK: Returns the field.
///
/// NOT_FOUND: The field is not present.
///
/// DATA_LOSS: The serialized message is not a valid protobuf.
///
/// FAILED_PRECONDITION: The field exists, but is not the correct type.
///
/// @endrst
inline Result<uint64_t> FindFixed64(ConstByteSpan message,
uint32_t field_number) {
return internal::Find<uint64_t, &Decoder::ReadFixed64>(message, field_number);
}
template <typename T, typename = std::enable_if_t<std::is_enum_v<T>>>
inline Result<uint64_t> FindFixed64(ConstByteSpan message, T field) {
return FindFixed64(message, static_cast<uint32_t>(field));
}
/// @brief Scans a serialized protobuf message for a `fixed64` field.
///
/// @param message_stream The serialized message to search.
/// @param field_number Protobuf field number of the field.
///
/// @returns @rst
///
/// .. pw-status-codes::
///
/// OK: Returns the field.
///
/// NOT_FOUND: The field is not present.
///
/// DATA_LOSS: The serialized message is not a valid protobuf.
///
/// FAILED_PRECONDITION: The field exists, but is not the correct type.
///
/// @endrst
inline Result<uint64_t> FindFixed64(stream::Reader& message_stream,
uint32_t field_number) {
return internal::Find<uint64_t, &StreamDecoder::ReadFixed64>(message_stream,
field_number);
}
template <typename T, typename = std::enable_if_t<std::is_enum_v<T>>>
inline Result<uint64_t> FindFixed64(stream::Reader& message_stream, T field) {
return FindFixed64(message_stream, static_cast<uint32_t>(field));
}
/// @brief Scans a serialized protobuf message for an `sfixed32` field.
///
/// @param message The serialized message to search.
/// @param field_number Protobuf field number of the field.
///
/// @returns @rst
///
/// .. pw-status-codes::
///
/// OK: Returns the field.
///
/// NOT_FOUND: The field is not present.
///
/// DATA_LOSS: The serialized message is not a valid protobuf.
///
/// FAILED_PRECONDITION: The field exists, but is not the correct type.
///
/// @endrst
inline Result<int32_t> FindSfixed32(ConstByteSpan message,
uint32_t field_number) {
return internal::Find<int32_t, &Decoder::ReadSfixed32>(message, field_number);
}
template <typename T, typename = std::enable_if_t<std::is_enum_v<T>>>
inline Result<int32_t> FindSfixed32(ConstByteSpan message, T field) {
return FindSfixed32(message, static_cast<uint32_t>(field));
}
/// @brief Scans a serialized protobuf message for an `sfixed32` field.
///
/// @param message_stream The serialized message to search.
/// @param field_number Protobuf field number of the field.
///
/// @returns @rst
///
/// .. pw-status-codes::
///
/// OK: Returns the field.
///
/// NOT_FOUND: The field is not present.
///
/// DATA_LOSS: The serialized message is not a valid protobuf.
///
/// FAILED_PRECONDITION: The field exists, but is not the correct type.
///
/// @endrst
inline Result<int32_t> FindSfixed32(stream::Reader& message_stream,
uint32_t field_number) {
return internal::Find<int32_t, &StreamDecoder::ReadSfixed32>(message_stream,
field_number);
}
template <typename T, typename = std::enable_if_t<std::is_enum_v<T>>>
inline Result<int32_t> FindSfixed32(stream::Reader& message_stream, T field) {
return FindSfixed32(message_stream, static_cast<uint32_t>(field));
}
/// @brief Scans a serialized protobuf message for an `sfixed64` field.
///
/// @param message The serialized message to search.
/// @param field_number Protobuf field number of the field.
///
/// @returns @rst
///
/// .. pw-status-codes::
///
/// OK: Returns the field.
///
/// NOT_FOUND: The field is not present.
///
/// DATA_LOSS: The serialized message is not a valid protobuf.
///
/// FAILED_PRECONDITION: The field exists, but is not the correct type.
///
/// @endrst
inline Result<int64_t> FindSfixed64(ConstByteSpan message,
uint32_t field_number) {
return internal::Find<int64_t, &Decoder::ReadSfixed64>(message, field_number);
}
template <typename T, typename = std::enable_if_t<std::is_enum_v<T>>>
inline Result<int64_t> FindSfixed64(ConstByteSpan message, T field) {
return FindSfixed64(message, static_cast<uint32_t>(field));
}
/// @brief Scans a serialized protobuf message for an `sfixed64` field.
///
/// @param message_stream The serialized message to search.
/// @param field_number Protobuf field number of the field.
///
/// @returns @rst
///
/// .. pw-status-codes::
///
/// OK: Returns the field.
///
/// NOT_FOUND: The field is not present.
///
/// DATA_LOSS: The serialized message is not a valid protobuf.
///
/// FAILED_PRECONDITION: The field exists, but is not the correct type.
///
/// @endrst
inline Result<int64_t> FindSfixed64(stream::Reader& message_stream,
uint32_t field_number) {
return internal::Find<int64_t, &StreamDecoder::ReadSfixed64>(message_stream,
field_number);
}
template <typename T, typename = std::enable_if_t<std::is_enum_v<T>>>
inline Result<int64_t> FindSfixed64(stream::Reader& message_stream, T field) {
return FindSfixed64(message_stream, static_cast<uint32_t>(field));
}
/// @brief Scans a serialized protobuf message for a `float` field.
///
/// @param message The serialized message to search.
/// @param field_number Protobuf field number of the field.
///
/// @returns @rst
///
/// .. pw-status-codes::
///
/// OK: Returns the field.
///
/// NOT_FOUND: The field is not present.
///
/// DATA_LOSS: The serialized message is not a valid protobuf.
///
/// FAILED_PRECONDITION: The field exists, but is not the correct type.
///
/// @endrst
inline Result<float> FindFloat(ConstByteSpan message, uint32_t field_number) {
return internal::Find<float, &Decoder::ReadFloat>(message, field_number);
}
template <typename T, typename = std::enable_if_t<std::is_enum_v<T>>>
inline Result<float> FindFloat(ConstByteSpan message, T field) {
return FindFloat(message, static_cast<uint32_t>(field));
}
/// @brief Scans a serialized protobuf message for a `float` field.
///
/// @param message_stream The serialized message to search.
/// @param field_number Protobuf field number of the field.
///
/// @returns @rst
///
/// .. pw-status-codes::
///
/// OK: Returns the field.
///
/// NOT_FOUND: The field is not present.
///
/// DATA_LOSS: The serialized message is not a valid protobuf.
///
/// FAILED_PRECONDITION: The field exists, but is not the correct type.
///
/// @endrst
inline Result<float> FindFloat(stream::Reader& message_stream,
uint32_t field_number) {
return internal::Find<float, &StreamDecoder::ReadFloat>(message_stream,
field_number);
}
template <typename T, typename = std::enable_if_t<std::is_enum_v<T>>>
inline Result<float> FindFloat(stream::Reader& message_stream, T field) {
return FindFloat(message_stream, static_cast<uint32_t>(field));
}
/// @brief Scans a serialized protobuf message for a `double` field.
///
/// @param message The serialized message to search.
/// @param field_number Protobuf field number of the field.
///
/// @returns @rst
///
/// .. pw-status-codes::
///
/// OK: Returns the field.
///
/// NOT_FOUND: The field is not present.
///
/// DATA_LOSS: The serialized message is not a valid protobuf.
///
/// FAILED_PRECONDITION: The field exists, but is not the correct type.
///
/// @endrst
inline Result<double> FindDouble(ConstByteSpan message, uint32_t field_number) {
return internal::Find<double, &Decoder::ReadDouble>(message, field_number);
}
template <typename T, typename = std::enable_if_t<std::is_enum_v<T>>>
inline Result<double> FindDouble(ConstByteSpan message, T field) {
return FindDouble(message, static_cast<uint32_t>(field));
}
/// @brief Scans a serialized protobuf message for a `double` field.
///
/// @param message_stream The serialized message to search.
/// @param field_number Protobuf field number of the field.
///
/// @returns @rst
///
/// .. pw-status-codes::
///
/// OK: Returns the field.
///
/// NOT_FOUND: The field is not present.
///
/// DATA_LOSS: The serialized message is not a valid protobuf.
///
/// FAILED_PRECONDITION: The field exists, but is not the correct type.
///
/// @endrst
inline Result<double> FindDouble(stream::Reader& message_stream,
uint32_t field_number) {
return internal::Find<double, &StreamDecoder::ReadDouble>(message_stream,
field_number);
}
template <typename T, typename = std::enable_if_t<std::is_enum_v<T>>>
inline Result<double> FindDouble(stream::Reader& message_stream, T field) {
return FindDouble(message_stream, static_cast<uint32_t>(field));
}
/// @brief Scans a serialized protobuf message for a `string` field.
///
/// @param message The serialized message to search.
/// @param field_number Protobuf field number of the field.
///
/// @returns @rst
///
/// .. pw-status-codes::
///
/// OK: Returns a subspan of the buffer containing the string field.
/// **NOTE**: The returned string is NOT null-terminated.
///
/// NOT_FOUND: The field is not present.
///
/// DATA_LOSS: The serialized message is not a valid protobuf.
///
/// FAILED_PRECONDITION: The field exists, but is not the correct type.
///
/// @endrst
inline Result<std::string_view> FindString(ConstByteSpan message,
uint32_t field_number) {
return internal::Find<std::string_view, &Decoder::ReadString>(message,
field_number);
}
template <typename T, typename = std::enable_if_t<std::is_enum_v<T>>>
inline Result<std::string_view> FindString(ConstByteSpan message, T field) {
return FindString(message, static_cast<uint32_t>(field));
}
/// @brief Scans a serialized protobuf message for a `string`field, copying its
/// data into the provided buffer.
///
/// @param message_stream The serialized message to search.
/// @param field_number Protobuf field number of the field.
/// @param out The buffer to which to write the string.
///
/// @returns @rst
///
/// .. pw-status-codes::
///
/// OK: Returns the size of the copied data.
/// **NOTE**: The returned string is NOT null-terminated.
///
/// NOT_FOUND: The field is not present.
///
/// DATA_LOSS: The serialized message is not a valid protobuf.
///
/// FAILED_PRECONDITION: The field exists, but is not the correct type.
///
/// @endrst
inline StatusWithSize FindString(stream::Reader& message_stream,
uint32_t field_number,
span<char> out) {
StreamDecoder decoder(message_stream);
Status status = internal::AdvanceToField(decoder, field_number);
if (!status.ok()) {
return StatusWithSize(status, 0);
}
StatusWithSize sws = decoder.ReadString(out);
// The StreamDecoder returns a NOT_FOUND if trying to read the wrong type for
// a field. Remap this to FAILED_PRECONDITION for consistency with the
// non-stream Find.
return sws.status().IsNotFound() ? StatusWithSize::FailedPrecondition() : sws;
}
/// @brief Scans a serialized protobuf message for a `string`field, copying its
/// data into the provided buffer.
///
/// @param message_stream The serialized message to search.
/// @param field_number Protobuf field number of the field.
/// @param out String to which to write the found value.
///
/// @returns @rst
///
/// .. pw-status-codes::
///
/// OK: Returns the size of the copied data.
///
/// NOT_FOUND: The field is not present.
///
/// DATA_LOSS: The serialized message is not a valid protobuf.
///
/// FAILED_PRECONDITION: The field exists, but is not the correct type.
///
/// @endrst
inline StatusWithSize FindString(stream::Reader& message_stream,
uint32_t field_number,
InlineString<>& out) {
StatusWithSize sws;
out.resize_and_overwrite([&](char* data, size_t size) {
sws = FindString(message_stream, field_number, span(data, size));
return sws.size();
});
return sws;
}
template <typename T, typename = std::enable_if_t<std::is_enum_v<T>>>
inline StatusWithSize FindString(stream::Reader& message_stream,
T field,
span<char> out) {
return FindString(message_stream, static_cast<uint32_t>(field), out);
}
template <typename T, typename = std::enable_if_t<std::is_enum_v<T>>>
inline StatusWithSize FindString(stream::Reader& message_stream,
T field,
InlineString<>& out) {
return FindString(message_stream, static_cast<uint32_t>(field), out);
}
/// @brief Scans a serialized protobuf message for a `bytes` field.
///
/// @param message The serialized message to search.
/// @param field_number Protobuf field number of the field.
///
/// @returns @rst
///
/// .. pw-status-codes::
///
/// OK: Returns the subspan of the buffer containing the bytes field.
///
/// NOT_FOUND: The field is not present.
///
/// DATA_LOSS: The serialized message is not a valid protobuf.
///
/// FAILED_PRECONDITION: The field exists, but is not the correct type.
///
/// @endrst
inline Result<ConstByteSpan> FindBytes(ConstByteSpan message,
uint32_t field_number) {
return internal::Find<ConstByteSpan, &Decoder::ReadBytes>(message,
field_number);
}
template <typename T, typename = std::enable_if_t<std::is_enum_v<T>>>
inline Result<ConstByteSpan> FindBytes(ConstByteSpan message, T field) {
return FindBytes(message, static_cast<uint32_t>(field));
}
/// @brief Scans a serialized protobuf message for a `bytes` field, copying its
/// data into the provided buffer.
///
/// @param message_stream The serialized message to search.
/// @param field_number Protobuf field number of the field.
///
/// @returns @rst
///
/// .. pw-status-codes::
///
/// OK: Returns the size of the copied data.
///
/// NOT_FOUND: The field is not present.
///
/// DATA_LOSS: The serialized message is not a valid protobuf.
///
/// FAILED_PRECONDITION: The field exists, but is not the correct type.
///
/// @endrst
inline StatusWithSize FindBytes(stream::Reader& message_stream,
uint32_t field_number,
ByteSpan out) {
StreamDecoder decoder(message_stream);
Status status = internal::AdvanceToField(decoder, field_number);
if (!status.ok()) {
return StatusWithSize(status, 0);
}
StatusWithSize sws = decoder.ReadBytes(out);
// The StreamDecoder returns a NOT_FOUND if trying to read the wrong type for
// a field. Remap this to FAILED_PRECONDITION for consistency with the
// non-stream Find.
return sws.status().IsNotFound() ? StatusWithSize::FailedPrecondition() : sws;
}
template <typename T, typename = std::enable_if_t<std::is_enum_v<T>>>
inline StatusWithSize FindBytes(stream::Reader& message_stream,
T field,
ByteSpan out) {
return FindBytes(message_stream, static_cast<uint32_t>(field), out);
}
/// @brief Scans a serialized protobuf message for a submessage.
///
/// @param message The serialized message to search.
/// @param field_number Protobuf field number of the field.
///
/// @returns @rst
///
/// .. pw-status-codes::
///
/// OK: Returns the subspan of the buffer containing the submessage.
///
/// NOT_FOUND: The field is not present.
///
/// DATA_LOSS: The serialized message is not a valid protobuf.
///
/// FAILED_PRECONDITION: The field exists, but is not the correct type.
///
/// @endrst
inline Result<ConstByteSpan> FindSubmessage(ConstByteSpan message,
uint32_t field_number) {
// On the wire, a submessage is identical to bytes. This function exists only
// to clarify users' intent.
return FindBytes(message, field_number);
}
template <typename T, typename = std::enable_if_t<std::is_enum_v<T>>>
inline Result<ConstByteSpan> FindSubmessage(ConstByteSpan message, T field) {
return FindSubmessage(message, static_cast<uint32_t>(field));
}
/// Returns a span containing the raw bytes of the value.
inline Result<ConstByteSpan> FindRaw(ConstByteSpan message,
uint32_t field_number) {
Decoder decoder(message);
PW_TRY(internal::AdvanceToField(decoder, field_number));
return decoder.RawFieldBytes();
}
template <typename T, typename = std::enable_if_t<std::is_enum_v<T>>>
Result<ConstByteSpan> FindRaw(ConstByteSpan message, T field) {
return FindRaw(message, static_cast<uint32_t>(field));
}
} // namespace pw::protobuf