// 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 #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() { protobuf::StreamDecoder decoder(field_reader_.Reset()); PW_TRY(decoder.Next()); return decoder.ReadUint32(); } template <> Int32 Message::Field::As() { protobuf::StreamDecoder decoder(field_reader_.Reset()); PW_TRY(decoder.Next()); return decoder.ReadInt32(); } template <> Sint32 Message::Field::As() { protobuf::StreamDecoder decoder(field_reader_.Reset()); PW_TRY(decoder.Next()); return decoder.ReadSint32(); } template <> Fixed32 Message::Field::As() { protobuf::StreamDecoder decoder(field_reader_.Reset()); PW_TRY(decoder.Next()); return decoder.ReadFixed32(); } template <> Sfixed32 Message::Field::As() { protobuf::StreamDecoder decoder(field_reader_.Reset()); PW_TRY(decoder.Next()); return decoder.ReadSfixed32(); } template <> Uint64 Message::Field::As() { protobuf::StreamDecoder decoder(field_reader_.Reset()); PW_TRY(decoder.Next()); return decoder.ReadUint64(); } template <> Int64 Message::Field::As() { protobuf::StreamDecoder decoder(field_reader_.Reset()); PW_TRY(decoder.Next()); return decoder.ReadInt64(); } template <> Sint64 Message::Field::As() { protobuf::StreamDecoder decoder(field_reader_.Reset()); PW_TRY(decoder.Next()); return decoder.ReadSint64(); } template <> Fixed64 Message::Field::As() { protobuf::StreamDecoder decoder(field_reader_.Reset()); PW_TRY(decoder.Next()); return decoder.ReadFixed64(); } template <> Sfixed64 Message::Field::As() { protobuf::StreamDecoder decoder(field_reader_.Reset()); PW_TRY(decoder.Next()); return decoder.ReadSfixed64(); } template <> Float Message::Field::As() { protobuf::StreamDecoder decoder(field_reader_.Reset()); PW_TRY(decoder.Next()); return decoder.ReadFloat(); } template <> Double Message::Field::As() { protobuf::StreamDecoder decoder(field_reader_.Reset()); PW_TRY(decoder.Next()); return decoder.ReadDouble(); } template <> Bool Message::Field::As() { protobuf::StreamDecoder decoder(field_reader_.Reset()); PW_TRY(decoder.Next()); return decoder.ReadBool(); } Result 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 res = bytes_reader.Read(buf); PW_TRY(res.status()); if (res.value().size() == 1) { if (buf[0] != bytes[i++]) return false; } } return true; } Result String::Equal(std::string_view str) { return Bytes::Equal(std::as_bytes(std::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 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(field_number); } RepeatedFieldParser Message::AsRepeatedStrings(uint32_t field_number) { return AsRepeated(field_number); } RepeatedFieldParser Message::AsRepeatedMessages( uint32_t field_number) { return AsRepeated(field_number); } StringMapParser Message::AsStringToMessageMap(uint32_t field_number) { return AsStringMap(field_number); } StringMapParser Message::AsStringToBytesMap(uint32_t field_number) { return AsStringMap(field_number); } StringMapParser Message::AsStringToStringMap(uint32_t field_number) { return AsStringMap(field_number); } } // namespace pw::protobuf