blob: 328f1ac4236865fa6a7f3123a892976383a6f690 [file] [log] [blame]
// Copyright 2018 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef RUNTIME_PROBE_PROBE_FUNCTION_ARGUMENT_H_
#define RUNTIME_PROBE_PROBE_FUNCTION_ARGUMENT_H_
#include <memory>
#include <set>
#include <string>
#include <utility>
#include <vector>
#include <base/check.h>
#include <base/logging.h>
#include <base/values.h>
namespace runtime_probe {
// To know how to define an argument parser and use it in your probe function,
// please check "functions/shell.h" as an example. It should be well commented.
//
// Currently, we only supports the following types of arguments:
// - std::string
// - int
// - bool
// - double
// - std::vector<std::string>
// - std::vector<std::unique_ptr<ProbeFunction>>
//
// Arguments can have default value, except for
// std::vector<std::unique_ptr<ProbeFunction>>.
class ProbeFunction;
template <typename T>
bool ParseArgumentInternal(const char* function_name,
const char* member_name,
T* member,
const base::Value& value);
template <typename T>
bool ParseArgument(const char* function_name,
const char* member_name,
T* member,
const base::Value& value) {
if (value.is_dict()) {
auto* real_value = value.FindKey(member_name);
if (!real_value) {
LOG(ERROR) << function_name << ": `" << member_name << "` not found";
return false;
}
return ParseArgumentInternal(function_name, member_name, member,
*real_value);
}
return ParseArgumentInternal(function_name, member_name, member, value);
}
template <typename T>
bool ParseArgument(const char* function_name,
const char* member_name,
T* member,
const base::Value& value,
const T&& default_value) {
CHECK(value.is_dict());
if (!value.FindKey(member_name)) {
*member = default_value;
return true;
}
return ParseArgument(function_name, member_name, member, value);
}
template <>
bool ParseArgument<std::vector<std::unique_ptr<ProbeFunction>>>(
const char* function_name,
const char* member_name,
std::vector<std::unique_ptr<ProbeFunction>>* member,
const base::Value& dict_value,
const std::vector<std::unique_ptr<ProbeFunction>>&& default_value) = delete;
// These macros are for argument parsing.
//
// 1. Due to the template declaration, the type of default value and member
// must match exactly. That is, the default value of a double argument
// must be double (3.0 instead of 3). And default value of string argument
// must be std::string{...}.
//
// 2. Due to the behavior of "&=", all parser will be executed even if some
// of them failed.
//
// See `functions/shell.h` for example usage.
// Assumes that |T| and |dict_value| are in the scope.
// Define |instance|, |keys| and |result| into the scope.
#define PARSE_BEGIN() \
base::Value raw_value{base::Value::Type::DICTIONARY}; \
raw_value.SetKey(T::function_name, dict_value.Clone()); \
auto instance = std::unique_ptr<T>{new T(std::move(raw_value))}; \
std::set<std::string> keys; \
bool result = true
// Parses each argument one by one. Stores the value into |instance->arg_name_|.
// If fail, sets |result| to false. Assumes that PARSE_BEGIN is called before
// this.
#define PARSE_ARGUMENT(member_name, ...) \
result &= \
ParseArgument(T::function_name, #member_name, &instance->member_name##_, \
dict_value, ##__VA_ARGS__); \
keys.insert(#member_name)
// Checks |result| and returns |instance| or nullptr. Assumes that PARSE_BEGIN
// is called before this.
// Notes that the return type must be |std::unique_ptr<T>| to support return
// type auto deduction.
#define PARSE_END() \
if (!result) \
return std::unique_ptr<T>{nullptr}; \
for (const auto kv : dict_value.DictItems()) { \
if (keys.find(kv.first) == keys.end()) { \
LOG(ERROR) << T::function_name << " doesn't have \"" << kv.first \
<< "\" argument."; \
return std::unique_ptr<T>{nullptr}; \
} \
} \
return instance
} // namespace runtime_probe
#endif // RUNTIME_PROBE_PROBE_FUNCTION_ARGUMENT_H_