910e62b5创建于 1月15日历史提交
// Copyright 2025 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef COMPONENTS_DBUS_UTILS_READ_VALUE_H_
#define COMPONENTS_DBUS_UTILS_READ_VALUE_H_

#include <utility>

#include "base/files/scoped_file.h"
#include "components/dbus/utils/types.h"
#include "components/dbus/utils/variant.h"
#include "dbus/message.h"
#include "dbus/object_path.h"

namespace dbus_utils {

// Deserializes a D-Bus type T from `reader`. Returns std::nullopt if the value
// could not be read. `reader` is advanced on success or failure.
template <typename T>
  requires IsSupportedDBusType<T>
std::optional<T> ReadValue(dbus::MessageReader& reader);

namespace internal {

template <typename T>
  requires IsSupportedDBusType<T>
std::optional<std::vector<T>> ReadArray(dbus::MessageReader& reader) {
  dbus::MessageReader array_reader(nullptr);
  if (!reader.PopArray(&array_reader)) {
    return std::nullopt;
  }
  std::vector<T> result;
  while (array_reader.HasMoreData()) {
    auto element = ReadValue<T>(array_reader);
    if (!element) {
      return std::nullopt;
    }
    result.emplace_back(std::move(*element));
  }
  return result;
}

template <typename K, typename V>
  requires IsSupportedDBusType<K> && IsSupportedDBusType<V>
std::optional<std::map<K, V>> ReadMap(dbus::MessageReader& reader) {
  dbus::MessageReader array_reader(nullptr);
  if (!reader.PopArray(&array_reader)) {
    return std::nullopt;
  }
  std::map<K, V> map;
  while (array_reader.HasMoreData()) {
    dbus::MessageReader dict_entry_reader(nullptr);
    if (!array_reader.PopDictEntry(&dict_entry_reader)) {
      return std::nullopt;
    }
    auto key = ReadValue<K>(dict_entry_reader);
    if (!key) {
      return std::nullopt;
    }
    auto value = ReadValue<V>(dict_entry_reader);
    if (!value) {
      return std::nullopt;
    }
    map.emplace(std::move(*key), std::move(*value));
  }
  return map;
}

template <typename T>
  requires IsSupportedStruct<T>::value
std::optional<T> ReadStruct(dbus::MessageReader& reader) {
  dbus::MessageReader struct_reader(nullptr);
  if (!reader.PopStruct(&struct_reader)) {
    return std::nullopt;
  }
  T s;
  const bool success = std::apply(
      [&](auto&... members) {
        auto read_and_assign = [&](auto& member) {
          using MemberType = std::remove_cvref_t<decltype(member)>;
          if (auto value = ReadValue<MemberType>(struct_reader)) {
            member = std::move(*value);
            return true;
          }
          return false;
        };
        return (read_and_assign(members) && ...);
      },
      s);
  if (!success || struct_reader.HasMoreData()) {
    return std::nullopt;
  }
  return s;
}

}  // namespace internal

template <typename T>
  requires IsSupportedDBusType<T>
std::optional<T> ReadValue(dbus::MessageReader& reader) {
  auto read_primitive =
      [&](bool (dbus::MessageReader::*pop)(T*)) -> std::optional<T> {
    T v;
    if (!(reader.*pop)(&v)) {
      return std::nullopt;
    }
    return v;
  };

  if constexpr (std::is_same_v<T, int16_t>) {
    return read_primitive(&dbus::MessageReader::PopInt16);
  } else if constexpr (std::is_same_v<T, uint16_t>) {
    return read_primitive(&dbus::MessageReader::PopUint16);
  } else if constexpr (std::is_same_v<T, int32_t>) {
    return read_primitive(&dbus::MessageReader::PopInt32);
  } else if constexpr (std::is_same_v<T, uint32_t>) {
    return read_primitive(&dbus::MessageReader::PopUint32);
  } else if constexpr (std::is_same_v<T, int64_t>) {
    return read_primitive(&dbus::MessageReader::PopInt64);
  } else if constexpr (std::is_same_v<T, uint64_t>) {
    return read_primitive(&dbus::MessageReader::PopUint64);
  } else if constexpr (std::is_same_v<T, bool>) {
    return read_primitive(&dbus::MessageReader::PopBool);
  } else if constexpr (std::is_same_v<T, double>) {
    return read_primitive(&dbus::MessageReader::PopDouble);
  } else if constexpr (std::is_same_v<T, uint8_t>) {
    return read_primitive(&dbus::MessageReader::PopByte);
  } else if constexpr (std::is_same_v<T, std::string>) {
    return read_primitive(&dbus::MessageReader::PopString);
  } else if constexpr (std::is_same_v<T, dbus::ObjectPath>) {
    return read_primitive(&dbus::MessageReader::PopObjectPath);
  } else if constexpr (std::is_same_v<T, base::ScopedFD>) {
    return read_primitive(&dbus::MessageReader::PopFileDescriptor);
  } else if constexpr (internal::IsSupportedArray<T>::value) {
    return internal::ReadArray<typename T::value_type>(reader);
  } else if constexpr (internal::IsSupportedMap<T>::value) {
    return internal::ReadMap<typename T::key_type, typename T::mapped_type>(
        reader);
  } else if constexpr (internal::IsSupportedStruct<T>::value) {
    return internal::ReadStruct<T>(reader);
  } else if constexpr (std::is_same_v<T, Variant>) {
    Variant variant;
    if (!variant.Read(reader)) {
      return std::nullopt;
    }
    return std::move(variant);
  } else {
    static_assert(false, "Unsupported type for D-Bus reading");
  }
}

}  // namespace dbus_utils

#endif  // COMPONENTS_DBUS_UTILS_READ_VALUE_H_