blob: ea2797d132b6f419a124dbeaabe6e42744c5df3c [file] [log] [blame]
// Copyright 2021 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.
#include "pw_protobuf/message.h"
#include <cstddef>
#include "pw_protobuf/serialized_size.h"
#include "pw_protobuf/stream_decoder.h"
#include "pw_result/result.h"
#include "pw_status/status_with_size.h"
#include "pw_stream/interval_reader.h"
#include "pw_stream/stream.h"
namespace pw::protobuf {
template <>
Uint32 Message::Field::As<Uint32>() {
protobuf::StreamDecoder decoder(field_reader_.Reset());
PW_TRY(decoder.Next());
return decoder.ReadUint32();
}
template <>
Int32 Message::Field::As<Int32>() {
protobuf::StreamDecoder decoder(field_reader_.Reset());
PW_TRY(decoder.Next());
return decoder.ReadInt32();
}
template <>
Sint32 Message::Field::As<Sint32>() {
protobuf::StreamDecoder decoder(field_reader_.Reset());
PW_TRY(decoder.Next());
return decoder.ReadSint32();
}
template <>
Fixed32 Message::Field::As<Fixed32>() {
protobuf::StreamDecoder decoder(field_reader_.Reset());
PW_TRY(decoder.Next());
return decoder.ReadFixed32();
}
template <>
Sfixed32 Message::Field::As<Sfixed32>() {
protobuf::StreamDecoder decoder(field_reader_.Reset());
PW_TRY(decoder.Next());
return decoder.ReadSfixed32();
}
template <>
Uint64 Message::Field::As<Uint64>() {
protobuf::StreamDecoder decoder(field_reader_.Reset());
PW_TRY(decoder.Next());
return decoder.ReadUint64();
}
template <>
Int64 Message::Field::As<Int64>() {
protobuf::StreamDecoder decoder(field_reader_.Reset());
PW_TRY(decoder.Next());
return decoder.ReadInt64();
}
template <>
Sint64 Message::Field::As<Sint64>() {
protobuf::StreamDecoder decoder(field_reader_.Reset());
PW_TRY(decoder.Next());
return decoder.ReadSint64();
}
template <>
Fixed64 Message::Field::As<Fixed64>() {
protobuf::StreamDecoder decoder(field_reader_.Reset());
PW_TRY(decoder.Next());
return decoder.ReadFixed64();
}
template <>
Sfixed64 Message::Field::As<Sfixed64>() {
protobuf::StreamDecoder decoder(field_reader_.Reset());
PW_TRY(decoder.Next());
return decoder.ReadSfixed64();
}
template <>
Float Message::Field::As<Float>() {
protobuf::StreamDecoder decoder(field_reader_.Reset());
PW_TRY(decoder.Next());
return decoder.ReadFloat();
}
template <>
Double Message::Field::As<Double>() {
protobuf::StreamDecoder decoder(field_reader_.Reset());
PW_TRY(decoder.Next());
return decoder.ReadDouble();
}
template <>
Bool Message::Field::As<Bool>() {
protobuf::StreamDecoder decoder(field_reader_.Reset());
PW_TRY(decoder.Next());
return decoder.ReadBool();
}
Result<bool> Bytes::Equal(ConstByteSpan bytes) {
stream::IntervalReader bytes_reader = GetBytesReader();
if (bytes_reader.interval_size() != bytes.size()) {
return false;
}
std::byte buf[1];
for (size_t i = 0; i < bytes.size();) {
Result<ByteSpan> res = bytes_reader.Read(buf);
PW_TRY(res.status());
if (res.value().size() == 1) {
if (buf[0] != bytes[i++])
return false;
}
}
return true;
}
Result<bool> String::Equal(std::string_view str) {
return Bytes::Equal(as_bytes(span{str}));
}
Message::iterator& Message::iterator::operator++() {
// If this is not a valid iterator, increment it to the end iterator,
// so loop will end.
if (!ok()) {
reader_.Exhaust();
eof_ = true;
return *this;
}
// Store the starting offset of the field.
size_t field_start = reader_.current();
protobuf::StreamDecoder decoder(reader_);
Status status = decoder.Next();
if (status.IsOutOfRange()) {
eof_ = true;
return *this;
} else if (!status.ok()) {
// In the case of error, invalidate the iterator. We don't immediately
// move the iterator to end(), so that calling code has a chance to catch
// the error.
status_ = status;
current_ = Field(status_);
return *this;
}
Result<uint32_t> field_number = decoder.FieldNumber();
// Consume the field so that the reader will be pointing to the start
// of the next field, which is equivalent to the end offset of the
// current field.
status = ConsumeCurrentField(decoder);
if (!status.ok()) {
status_ = status;
current_ = Field(status_);
return *this;
}
// Create a Field object with the field interval.
current_ = Field(stream::IntervalReader(
reader_.source_reader(), field_start, reader_.current()),
field_number.value());
return *this;
}
Message::iterator Message::begin() {
if (!ok()) {
return end();
}
return iterator(reader_.Reset());
}
Message::iterator Message::end() {
// The end iterator is created by using an exahusted stream::IntervalReader,
// i.e. the reader is pointing at the internval end.
stream::IntervalReader reader_end = reader_;
return iterator(reader_end.Exhaust());
}
RepeatedBytes Message::AsRepeatedBytes(uint32_t field_number) {
return AsRepeated<Bytes>(field_number);
}
RepeatedFieldParser<String> Message::AsRepeatedStrings(uint32_t field_number) {
return AsRepeated<String>(field_number);
}
RepeatedFieldParser<Message> Message::AsRepeatedMessages(
uint32_t field_number) {
return AsRepeated<Message>(field_number);
}
StringMapParser<Message> Message::AsStringToMessageMap(uint32_t field_number) {
return AsStringMap<Message>(field_number);
}
StringMapParser<Bytes> Message::AsStringToBytesMap(uint32_t field_number) {
return AsStringMap<Bytes>(field_number);
}
StringMapParser<String> Message::AsStringToStringMap(uint32_t field_number) {
return AsStringMap<String>(field_number);
}
} // namespace pw::protobuf