mysqlshdk/include/scripting/types.h (725 lines of code) (raw):
/*
* Copyright (c) 2014, 2024, Oracle and/or its affiliates.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License, version 2.0,
* as published by the Free Software Foundation.
*
* This program is designed to work with certain software (including
* but not limited to OpenSSL) that is licensed under separate terms,
* as designated in a particular file or component or in included license
* documentation. The authors of MySQL hereby grant you an additional
* permission to link the program and your derivative works with the
* separately licensed software that they have either included with
* the program or referenced in the documentation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
* the GNU General Public License, version 2.0, for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef MYSQLSHDK_INCLUDE_SCRIPTING_TYPES_H_
#define MYSQLSHDK_INCLUDE_SCRIPTING_TYPES_H_
#include "types_common.h"
#include <algorithm>
#include <cassert>
#include <iterator>
#include <list>
#include <map>
#include <memory>
#include <optional>
#include <set>
#include <stdexcept>
#include <string>
#include <string_view>
#include <unordered_set>
#include <utility>
#include <vector>
#include "mysqlshdk/include/mysqlshdk_export.h"
#include "mysqlshdk/libs/utils/error.h"
#include "mysqlshdk/libs/utils/nullable.h"
// For error codes used by the shell
#define SHERR_FIRST 50000
namespace shcore {
/** Basic types that can be passed around code in different languages.
With the exception of Native and Function, all types can be serialized to JSON.
*/
enum Value_type {
Undefined, //! Undefined
Null, //! Null/None value
Bool, //! true or false
String, //! String values, UTF-8 encoding
Integer, //! 64bit integer numbers
UInteger, //! unsigned 64bit integer numbers
Float, //! double numbers
Object, //! Native/bridged C++ object refs, may or may not be serializable
Array, //! Array/List container
Map, //! Dictionary/Map/Object container
MapRef, //! A weak reference to a Map
Function, //! A function reference, not serializable.
Binary //! Binary data
};
bool is_compatible_type(Value_type source_type, Value_type target_type);
std::string type_description(Value_type type);
std::string SHCORE_PUBLIC type_name(Value_type type);
class Object_bridge;
typedef std::shared_ptr<Object_bridge> Object_bridge_ref;
/** Pointer to a function that may be implemented in any language.
*/
class Function_base;
using Function_base_ref = std::shared_ptr<Function_base>;
/** A generic value that can be used from any language we support.
Anything that can be represented using this can be passed as a parameter to
scripting functions or stored in the internal registry or anywhere. If
serializable types are used, then they may also be stored as a JSON document.
Values are exposed to scripting languages according to the following rules:
- Simple types (Null, Bool, String, Integer, Float, UInteger) are converted
directly to the target type, both ways
- Arrays and Maps are converted directly to the target type, both ways
- Functions are wrapped into callable objects from C++ to scripting language
- Scripting language functions are wrapped into an instance of a language
specific subclass of Function_base
- C++ Objects are generically wrapped into a scripting language object, except
when there's a specific native counterpart
- Scripting language objects are either generically wrapped to a language
specific generic object wrapper or converted to a specific C++ Object subclass
Example: JS Date object is converted to a C++ Date object and vice-versa, but
Mysql_connection is wrapped generically
@section Implicit type conversions
Null Bool String Integer UInteger Float Object Array Map
Null OK - - - - - OK OK OK
Bool - OK - OK OK OK - - -
String - OK OK OK OK OK - - -
Integer - OK - OK OK OK - - -
UInteger - OK - OK OK OK - - -
Float - OK - OK OK OK - - -
Object - - - - - - OK - -
Array - - - - - - - OK -
Map - - - - - - - - OK
* Integer <-> UInteger conversions are only possible if the range allows it
* Null can be cast to Object/Array/Map, but a valid Object/Array/Map pointer
is not NULL, so it can't be cast to it.
*/
struct SHCORE_PUBLIC Value {
typedef std::vector<Value> Array_type;
typedef std::shared_ptr<Array_type> Array_type_ref;
class SHCORE_PUBLIC Map_type {
public:
typedef std::map<std::string, Value> container_type;
typedef container_type::const_iterator const_iterator;
typedef container_type::iterator iterator;
using value_type = container_type::value_type;
using reverse_iterator = container_type::reverse_iterator;
using const_reverse_iterator = container_type::const_reverse_iterator;
inline bool has_key(const std::string &k) const { return find(k) != end(); }
Value_type get_type(const std::string &k) const;
bool is_null(const std::string &k) const {
return get_type(k) == shcore::Null;
}
std::string get_string(const std::string &k,
const std::string &def = "") const;
bool get_bool(const std::string &k, bool def = false) const;
int64_t get_int(const std::string &k, int64_t def = 0) const;
uint64_t get_uint(const std::string &k, uint64_t def = 0) const;
double get_double(const std::string &k, double def = 0.0) const;
std::shared_ptr<Value::Map_type> get_map(
const std::string &k,
std::shared_ptr<Map_type> def = std::shared_ptr<Map_type>()) const;
std::shared_ptr<Value::Array_type> get_array(
const std::string &k,
std::shared_ptr<Array_type> def = std::shared_ptr<Array_type>()) const;
void merge_contents(std::shared_ptr<Map_type> source, bool overwrite);
template <class C>
std::shared_ptr<C> get_object(
const std::string &k,
std::shared_ptr<C> def = std::shared_ptr<C>()) const {
const_iterator iter = find(k);
if (iter == end()) return def;
iter->second.check_type(Object);
return iter->second.as_object<C>();
}
const_iterator find(const std::string &k) const { return _map.find(k); }
iterator find(const std::string &k) { return _map.find(k); }
size_t erase(const std::string &k) { return _map.erase(k); }
iterator erase(const_iterator it) { return _map.erase(it); }
iterator erase(iterator it) { return _map.erase(it); }
void clear() { _map.clear(); }
const_iterator begin() const { return _map.begin(); }
iterator begin() { return _map.begin(); }
const_reverse_iterator rbegin() const { return _map.rbegin(); }
reverse_iterator rbegin() { return _map.rbegin(); }
const_iterator end() const { return _map.end(); }
iterator end() { return _map.end(); }
const_reverse_iterator rend() const { return _map.rend(); }
reverse_iterator rend() { return _map.rend(); }
void set(const std::string &k, shcore::Value &&v) {
_map[k] = std::move(v);
}
void set(const std::string &k, const shcore::Value &v) { _map[k] = v; }
const container_type::mapped_type &at(const std::string &k) const {
return _map.at(k);
}
container_type::mapped_type &operator[](const std::string &k) {
return _map[k];
}
bool operator==(const Map_type &other) const { return _map == other._map; }
bool operator<(const Map_type &other) const { return _map < other._map; }
bool operator<=(const Map_type &other) const { return _map <= other._map; }
bool empty() const { return _map.empty(); }
size_t size() const { return _map.size(); }
size_t count(const std::string &k) const { return _map.count(k); }
template <class T>
std::pair<iterator, bool> emplace(const std::string &key, T &&v) {
return _map.emplace(key, Value(std::forward<T>(v)));
}
private:
container_type _map;
};
typedef std::shared_ptr<Map_type> Map_type_ref;
Value_type type{Undefined};
union {
bool b;
std::string *s;
int64_t i;
uint64_t ui;
double d;
std::shared_ptr<class Object_bridge> *o;
std::shared_ptr<Array_type> *array;
std::shared_ptr<Map_type> *map;
std::weak_ptr<Map_type> *mapref;
std::shared_ptr<class Function_base> *func;
} value;
Value() = default;
Value(const Value ©) { *this = copy; }
Value(Value &&other) noexcept { *this = std::move(other); }
explicit Value(const std::string &s, bool binary = false);
explicit Value(std::string &&s, bool binary = false);
explicit Value(const char *);
explicit Value(const char *, size_t n, bool binary = false);
explicit Value(std::string_view s, bool binary = false);
explicit Value(std::wstring_view s);
explicit Value(std::nullptr_t);
explicit Value(int i);
explicit Value(unsigned int ui);
explicit Value(int64_t i);
explicit Value(uint64_t ui);
explicit Value(float f);
explicit Value(double d);
explicit Value(bool b);
explicit Value(const std::shared_ptr<Function_base> &f);
explicit Value(std::shared_ptr<Function_base> &&f);
explicit Value(const std::shared_ptr<Object_bridge> &o);
explicit Value(std::shared_ptr<Object_bridge> &&o);
explicit Value(const std::weak_ptr<Map_type> &n);
explicit Value(std::weak_ptr<Map_type> &&n);
explicit Value(const Map_type_ref &n);
explicit Value(Map_type_ref &&n);
explicit Value(const Array_type_ref &n);
explicit Value(Array_type_ref &&n);
static Value wrap(Object_bridge *o) {
return Value(std::shared_ptr<Object_bridge>(o));
}
template <class T>
static Value wrap(std::shared_ptr<T> o) {
return Value(std::static_pointer_cast<Object_bridge>(std::move(o)));
}
static Value new_array() {
return Value(std::shared_ptr<Array_type>(new Array_type()));
}
static Value new_map() {
return Value(std::shared_ptr<Map_type>(new Map_type()));
}
static Value Null() {
Value v;
v.type = shcore::Null;
return v;
}
static Value True() {
Value v;
v.type = shcore::Bool;
v.value.b = true;
return v;
}
static Value False() {
Value v;
v.type = shcore::Bool;
v.value.b = false;
return v;
}
//! parse a string returned by repr() back into a Value
static Value parse(const std::string &s);
static Value parse(const char *s, size_t length);
~Value() noexcept;
Value &operator=(const Value &other);
Value &operator=(Value &&other) noexcept;
bool operator==(const Value &other) const;
bool operator!=(const Value &other) const { return !(*this == other); }
bool operator<(const Value &other) const;
bool operator<=(const Value &other) const;
bool operator>(const Value &other) const { return !(*this <= other); }
bool operator>=(const Value &other) const { return !(*this < other); }
explicit operator bool() const {
return type != Undefined && type != shcore::Null;
}
// helper used by gtest
friend std::ostream &operator<<(std::ostream &os, const Value &v);
//! returns a human-readable description text for the value.
// if pprint is true, it will try to pretty-print it (like adding newlines)
std::string descr(bool pprint = false) const;
//! returns a string representation of the serialized object, suitable to be
//! passed to parse()
std::string repr() const;
//! returns a JSON representation of the object
std::string json(bool pprint = false) const;
//! returns a YAML representation of the Value
std::string yaml() const;
std::string &append_descr(std::string &s_out, int indent = -1,
char quote_strings = '\0') const;
std::string &append_repr(std::string &s_out) const;
void check_type(Value_type t) const;
Value_type get_type() const { return type; }
bool as_bool() const;
int64_t as_int() const;
uint64_t as_uint() const;
double as_double() const;
std::string as_string() const;
std::wstring as_wstring() const;
const std::string &get_string() const {
check_type(String);
return *value.s;
}
template <class C>
std::shared_ptr<C> as_object() const {
check_type(Object);
return std::dynamic_pointer_cast<C>(type == shcore::Null ? nullptr
: *value.o);
}
std::shared_ptr<Object_bridge> as_object() const {
check_type(Object);
return std::dynamic_pointer_cast<Object_bridge>(
type == shcore::Null ? nullptr : *value.o);
}
std::shared_ptr<Map_type> as_map() const {
check_type(Map);
return type == shcore::Null ? nullptr : *value.map;
}
std::shared_ptr<Array_type> as_array() const {
check_type(Array);
return type == shcore::Null ? nullptr : *value.array;
}
template <class C>
C to_string_container() const {
C vec;
auto arr = as_array();
if (arr) {
std::transform(arr->begin(), arr->end(), std::inserter<C>(vec, vec.end()),
[](const shcore::Value &v) { return v.get_string(); });
}
return vec;
}
std::map<std::string, std::string> to_string_map() const {
std::map<std::string, std::string> map;
check_type(Map);
for (const auto &v : *as_map()) {
map.emplace(v.first, v.second.get_string());
}
return map;
}
template <class C>
std::map<std::string, C> to_container_map() const {
std::map<std::string, C> map;
check_type(Map);
for (const auto &v : *as_map()) {
map.emplace(v.first, v.second.to_string_container<C>());
}
return map;
}
std::shared_ptr<Function_base> as_function() const {
check_type(Function);
return std::dynamic_pointer_cast<Function_base>(
type == shcore::Null ? nullptr : *value.func);
}
private:
static Value parse(const char **pc);
static Value parse_map(const char **pc);
static Value parse_array(const char **pc);
static Value parse_string(const char **pc, char quote);
static Value parse_single_quoted_string(const char **pc);
static Value parse_double_quoted_string(const char **pc);
static Value parse_number(const char **pc);
std::string yaml(int indent) const;
};
typedef Value::Map_type_ref Dictionary_t;
typedef Value::Array_type_ref Array_t;
inline Dictionary_t make_dict() { return std::make_shared<Value::Map_type>(); }
template <typename K, typename V, typename... Arg>
inline Dictionary_t make_dict(K &&key, V &&value, Arg &&...args) {
Dictionary_t dict = make_dict(std::forward<Arg>(args)...);
dict->emplace(std::forward<K>(key), std::forward<V>(value));
return dict;
}
inline Array_t make_array() { return std::make_shared<Value::Array_type>(); }
template <typename... Arg>
inline Array_t make_array(Arg &&...args) {
auto array = make_array();
(void)std::initializer_list<int>{
(array->emplace_back(std::forward<Arg>(args)), 0)...};
return array;
}
template <template <typename...> class C, typename T>
inline Array_t make_array(const C<T> &container) {
auto array = make_array();
for (const auto &item : container) {
array->emplace_back(item);
}
return array;
}
template <template <typename...> class C, typename T>
inline Array_t make_array(C<T> &&container) {
auto array = make_array();
for (auto &item : container) {
array->emplace_back(std::move(item));
}
return array;
}
class SHCORE_PUBLIC Exception : public shcore::Error {
std::shared_ptr<Value::Map_type> _error;
public:
Exception(const std::string &message, int code,
const std::shared_ptr<Value::Map_type> &e);
Exception(const std::string &message, int code);
Exception(const std::string &type, const std::string &message, int code);
virtual ~Exception() noexcept {}
static Exception runtime_error(const std::string &message);
static Exception argument_error(const std::string &message);
static Exception attrib_error(const std::string &message);
static Exception value_error(const std::string &message);
static Exception type_error(const std::string &message);
static Exception logic_error(const std::string &message);
static Exception metadata_error(const std::string &message);
static Exception external_action_required(const std::string &message);
static Exception mysql_error_with_code(const std::string &message, int code) {
return error_with_code("MySQL Error", message, code);
}
static Exception mysql_error_with_code_and_state(const std::string &message,
int code,
const char *sqlstate) {
return error_with_code_and_state("MySQL Error", message, code, sqlstate);
}
static Exception error_with_code(const std::string &type,
const std::string &message, int code);
static Exception error_with_code_and_state(const std::string &type,
const std::string &message,
int code, const char *sqlstate);
static Exception parser_error(const std::string &message);
static Exception scripting_error(const std::string &message);
void set_file_context(const std::string &file, size_t line);
bool is_argument() const;
bool is_attribute() const;
bool is_value() const;
bool is_type() const;
bool is_mysql() const;
bool is_mysqlsh() const;
bool is_parser() const;
bool is_runtime() const;
bool is_metadata() const;
const char *type() const noexcept;
std::shared_ptr<Value::Map_type> error() const { return _error; }
std::string format() const override;
};
class SHCORE_PUBLIC Argument_list {
public:
// TODO(alfredo) remove most of this when possible
const std::string &string_at(unsigned int i) const;
bool bool_at(unsigned int i) const;
int64_t int_at(unsigned int i) const;
uint64_t uint_at(unsigned int i) const;
double double_at(unsigned int i) const;
template <class C>
std::shared_ptr<C> object_at(unsigned int i) const {
std::shared_ptr<C> ret_val;
try {
auto object = object_at(i);
ret_val = std::dynamic_pointer_cast<C>(object);
} catch (...) {
// We don't care, return value will be empty
}
return ret_val;
}
std::shared_ptr<Object_bridge> object_at(unsigned int i) const;
std::shared_ptr<Value::Map_type> map_at(unsigned int i) const;
std::shared_ptr<Value::Array_type> array_at(unsigned int i) const;
void ensure_count(unsigned int c, const char *context) const;
void ensure_count(unsigned int minc, unsigned int maxc,
const char *context) const;
void ensure_at_least(unsigned int minc, const char *context) const;
void push_back(const Value &value) { _args.push_back(value); }
void pop_back() { _args.pop_back(); }
size_t size() const { return _args.size(); }
const Value &at(size_t i) const { return _args.at(i); }
Value &operator[](size_t i) { return _args[i]; }
const Value &operator[](size_t i) const { return _args[i]; }
void clear() { _args.clear(); }
bool empty() const { return _args.empty(); }
std::vector<Value>::const_iterator begin() const { return _args.begin(); }
std::vector<Value>::const_iterator end() const { return _args.end(); }
bool operator==(const Argument_list &other) const;
template <class T>
void emplace_back(const T &value) {
_args.emplace_back(Value(value));
}
private:
std::vector<Value> _args;
};
class SHCORE_PUBLIC Argument_map {
public:
Argument_map();
Argument_map(const Value::Map_type &map);
const std::string &string_at(const std::string &key) const;
bool bool_at(const std::string &key) const;
int64_t int_at(const std::string &key) const;
uint64_t uint_at(const std::string &key) const;
double double_at(const std::string &key) const;
std::shared_ptr<Object_bridge> object_at(const std::string &key) const;
std::shared_ptr<Value::Map_type> map_at(const std::string &key) const;
std::shared_ptr<Value::Array_type> array_at(const std::string &key) const;
template <class C>
std::shared_ptr<C> object_at(const std::string &key) const {
std::shared_ptr<C> ret_val;
try {
auto object = object_at(key);
ret_val = std::dynamic_pointer_cast<C>(object);
} catch (...) {
// We don't care, return value will be empty
}
return ret_val;
}
void ensure_keys(const std::set<std::string> &mandatory_keys,
const std::set<std::string> &optional_keys,
const char *context, bool case_sensitive = true) const;
bool validate_keys(const std::set<std::string> &mandatory_keys,
const std::set<std::string> &optional_keys,
std::vector<std::string> &missing_keys,
std::vector<std::string> &invalid_keys,
bool case_sensitive = true) const;
size_t size() const { return _map.size(); }
const Value &at(const std::string &key) const { return _map.at(key); }
Value &operator[](const std::string &key) { return _map[key]; }
void clear() { _map.clear(); }
bool has_key(const std::string &key) const { return _map.has_key(key); }
const Value::Map_type &as_map() const { return _map; }
private:
Value::Map_type _map;
static bool comp(const std::string &lhs, const std::string &rhs);
static bool icomp(const std::string &lhs, const std::string &rhs);
};
template <class T>
struct value_type_for_native {};
template <>
struct value_type_for_native<bool> {
static const Value_type type = Bool;
static bool extract(const Value &value) { return value.as_bool(); }
};
template <>
struct value_type_for_native<int> {
static const Value_type type = Integer;
static int extract(const Value &value) {
return static_cast<int>(value.as_int());
}
};
template <>
struct value_type_for_native<unsigned int> {
static const Value_type type = UInteger;
static unsigned int extract(const Value &value) {
return static_cast<unsigned int>(value.as_uint());
}
};
template <>
struct value_type_for_native<long int> {
static const Value_type type = Integer;
static long int extract(const Value &value) {
return static_cast<long int>(value.as_int());
}
};
template <>
struct value_type_for_native<unsigned long int> {
static const Value_type type = UInteger;
static unsigned long int extract(const Value &value) {
return static_cast<unsigned long int>(value.as_uint());
}
};
template <>
struct value_type_for_native<long long int> {
static const Value_type type = Integer;
static long long int extract(const Value &value) {
return static_cast<long long int>(value.as_int());
}
};
template <>
struct value_type_for_native<unsigned long long int> {
static const Value_type type = UInteger;
static unsigned long long int extract(const Value &value) {
return static_cast<unsigned long long int>(value.as_uint());
}
};
template <>
struct value_type_for_native<double> {
static const Value_type type = Float;
static double extract(const Value &value) { return value.as_double(); }
};
template <>
struct value_type_for_native<std::string> {
static const Value_type type = String;
static std::string extract(const Value &value) { return value.as_string(); }
};
template <>
struct value_type_for_native<const std::string> {
static const Value_type type = String;
static std::string extract(const Value &value) { return value.as_string(); }
};
template <>
struct value_type_for_native<std::vector<std::string>> {
static const Value_type type = Array;
static std::vector<std::string> extract(const Value &value) {
return value.to_string_container<std::vector<std::string>>();
}
};
template <>
struct value_type_for_native<const std::vector<std::string> &> {
static const Value_type type = Array;
static std::vector<std::string> extract(const Value &value) {
return value.to_string_container<std::vector<std::string>>();
}
};
template <>
struct value_type_for_native<std::list<std::string>> {
static const Value_type type = Array;
static std::list<std::string> extract(const Value &value) {
return value.to_string_container<std::list<std::string>>();
}
};
template <>
struct value_type_for_native<std::set<std::string>> {
static const Value_type type = Array;
static std::set<std::string> extract(const Value &value) {
return value.to_string_container<std::set<std::string>>();
}
};
template <>
struct value_type_for_native<std::unordered_set<std::string>> {
static const Value_type type = Array;
static std::unordered_set<std::string> extract(const Value &value) {
return value.to_string_container<std::unordered_set<std::string>>();
}
};
template <>
struct value_type_for_native<std::map<std::string, std::string>> {
static const Value_type type = Map;
static std::map<std::string, std::string> extract(const Value &value) {
return value.to_string_map();
}
};
template <class C>
struct value_type_for_native<std::map<std::string, C>> {
static const Value_type type = Map;
static std::map<std::string, C> extract(const Value &value) {
return value.to_container_map<C>();
}
};
template <>
struct value_type_for_native<Object_bridge *> {
static const Value_type type = Object;
};
template <>
struct value_type_for_native<Object_bridge_ref> {
static const Value_type type = Object;
static Object_bridge_ref extract(const Value &value) {
return value.as_object();
}
};
template <>
struct value_type_for_native<Value::Map_type> {
static const Value_type type = Map;
};
template <>
struct value_type_for_native<Dictionary_t> {
static const Value_type type = Map;
static Dictionary_t extract(const Value &value) { return value.as_map(); }
};
template <>
struct value_type_for_native<Value::Array_type> {
static const Value_type type = Array;
};
template <>
struct value_type_for_native<Array_t> {
static const Value_type type = Array;
static Array_t extract(const Value &value) { return value.as_array(); }
};
template <>
struct value_type_for_native<Value> {
static const Value_type type = Undefined;
static Value extract(const Value &value) { return value; }
};
template <typename T>
struct value_type_for_native<mysqlshdk::utils::nullable<T>> {
static const Value_type type = value_type_for_native<T>::type;
static T extract(const Value &value) {
return value_type_for_native<T>::extract(value);
}
};
template <typename T>
struct value_type_for_native<std::optional<T>> {
static const Value_type type = value_type_for_native<T>::type;
static T extract(const Value &value) {
return value_type_for_native<T>::extract(value);
}
};
template <>
struct value_type_for_native<Function_base_ref> {
static const Value_type type = Function;
static shcore::Function_base_ref extract(const Value &value) {
return value.as_function();
}
};
// Extract option values from an options dictionary, with validations
// Replaces Argument_map
class Option_unpacker {
public:
Option_unpacker() = default;
explicit Option_unpacker(const Dictionary_t &options);
virtual ~Option_unpacker() {}
// For external unpacker objects
template <typename T>
Option_unpacker &unpack(T *extra) {
extra->unpack(this);
return *this;
}
// Extract required option
template <typename T>
Option_unpacker &required(const char *name, T *out_value) {
extract_value<T>(name, out_value,
get_required(name, value_type_for_native<T>::type));
return *this;
}
// Extract optional option
template <typename T>
Option_unpacker &optional(const char *name, T *out_value) {
extract_value<T>(name, out_value,
get_optional(name, value_type_for_native<T>::type));
return *this;
}
// Extract optional option with exact type (no conversions)
template <typename T>
Option_unpacker &optional_exact(const char *name, T *out_value) {
extract_value<T>(name, out_value,
get_optional_exact(name, value_type_for_native<T>::type));
return *this;
}
// Case insensitive
template <typename T>
Option_unpacker &optional_ci(const char *name, T *out_value) {
extract_value<T>(name, out_value,
get_optional(name, value_type_for_native<T>::type, true));
return *this;
}
void end(const std::string &context = "");
void set_options(const shcore::Dictionary_t &options);
const shcore::Dictionary_t &options() const { return m_options; }
protected:
Dictionary_t m_options;
std::set<std::string> m_unknown;
std::set<std::string> m_missing;
template <typename T, typename S>
void extract_value(const char *name, S *out_value, const Value &value) {
if (value) {
try {
*out_value = value_type_for_native<T>::extract(value);
} catch (const std::exception &e) {
std::string msg = e.what();
if (msg.compare(0, 18, "Invalid typecast: ") == 0) msg = msg.substr(18);
throw Exception::type_error(std::string("Option '") + name + "' " +
msg);
}
}
}
Value get_required(const char *name, Value_type type);
Value get_optional(const char *name, Value_type type,
bool case_insensitive = false);
Value get_optional_exact(const char *name, Value_type type,
bool case_insensitive = false);
void validate(const std::string &context = "");
};
class JSON_dumper;
/** An instance of an object, that's implemented in some language.
*
* Objects of this type can be interacted with through it's accessor methods
* can be used as generic object wrappers/references.
*
* They can be instantiated through their Metaclass factory
*/
class SHCORE_PUBLIC Object_bridge {
public:
virtual ~Object_bridge() = default;
virtual std::string class_name() const = 0;
//! Appends JSON representation of the object if supported
virtual void append_json(JSON_dumper &dumper) const;
//! Appends descriptive text to the string, suitable for showing to the user
virtual std::string &append_descr(std::string &s_out, int indent = -1,
int quote_strings = 0) const = 0;
//! Returns a representation of the object suitable to be passed to a Factory
// constructor of this object, which would create an equivalent instance of
// the object Format for repr() of Native_objects must follow this pattern:
// <Typename:data> where Typename is the same name used to register the type
virtual std::string &append_repr(std::string &s_out) const = 0;
//! Returns the list of members that this object has
virtual std::vector<std::string> get_members() const = 0;
//! Implements equality operator
virtual bool operator==(const Object_bridge &other) const = 0;
virtual bool operator!=(const Object_bridge &other) const {
return !(*this == other);
}
virtual bool operator<(const Object_bridge &) const { return false; }
virtual bool operator<=(const Object_bridge &other) const {
return (*this < other) || (*this == other);
}
//! Returns the value of a member
virtual Value get_member(const std::string &prop) const = 0;
//! Verifies if the object has a member
virtual bool has_member(const std::string &prop) const = 0;
//! Sets the value of a member
virtual void set_member(const std::string &prop, Value value) = 0;
//! Returns the value of a member
virtual bool is_indexed() const = 0;
//! Returns the value of a member
virtual Value get_member(size_t index) const = 0;
//! Sets the value of a member
virtual void set_member(size_t index, Value value) = 0;
//! Returns the number of indexable members
virtual size_t length() const = 0;
//! Returns true if a method with the given name exists.
virtual bool has_method(const std::string &name) const = 0;
//! Calls the named method with the given args
virtual Value call(const std::string &name, const Argument_list &args) = 0;
};
class SHCORE_PUBLIC Function_base {
public:
Function_base() = default;
Function_base(const Function_base &other) = default;
Function_base(Function_base &&other) = default;
Function_base &operator=(const Function_base &other) = default;
Function_base &operator=(Function_base &&other) = default;
virtual ~Function_base() = default;
//! The name of the function
virtual const std::string &name() const = 0;
//! Returns the signature of the function, as a list of
// argname - description, Type pairs
virtual const std::vector<std::pair<std::string, Value_type>> &signature()
const = 0;
//! Return type of the function, as a description, Type pair
virtual Value_type return_type() const = 0;
//! Implements equality operator
virtual bool operator==(const Function_base &other) const = 0;
//! Invokes the function and passes back the return value.
// arglist must match the signature
virtual Value invoke(const Argument_list &args) = 0;
virtual std::string &append_descr(std::string *s_out, int indent = -1,
int quote_strings = 0) const;
virtual std::string &append_repr(std::string *s_out) const;
virtual void append_json(JSON_dumper *dumper) const;
};
bool my_strnicmp(const char *c1, const char *c2, size_t n);
} // namespace shcore
#endif // MYSQLSHDK_INCLUDE_SCRIPTING_TYPES_H_