#ifndef Rice__Data_Object__ipp_ #define Rice__Data_Object__ipp_ #include "Data_Type_defn.hpp" #include namespace Rice { template Exception create_type_exception(VALUE value) { return Exception(rb_eTypeError, "Wrong argument type. Expected: %s. Received: %s.", detail::protect(rb_class2name, Data_Type::klass().value()), detail::protect(rb_obj_classname, value)); } template inline Data_Object::Data_Object(T& data, bool isOwner, Class klass) { VALUE value = detail::wrap(klass, Data_Type::ruby_data_type(), data, isOwner); this->set_value(value); } template inline Data_Object::Data_Object(T* data, bool isOwner, Class klass) { VALUE value = detail::wrap(klass, Data_Type::ruby_data_type(), data, isOwner); this->set_value(value); } template inline Data_Object::Data_Object(Object value) : Object(value) { check_ruby_type(value); } template inline void Data_Object::check_ruby_type(VALUE value) { if (rb_obj_is_kind_of(value, Data_Type::klass()) == Qfalse) { throw create_type_exception(value); } } template inline T& Data_Object::operator*() const { return *this->get(); } template inline T* Data_Object::operator->() const { return this->get(); } template inline T* Data_Object::get() const { if (this->value() == Qnil) { return nullptr; } else { return detail::unwrap(this->value(), Data_Type::ruby_data_type()); } } template inline T* Data_Object::from_ruby(VALUE value) { if (Data_Type::is_descendant(value)) { return detail::unwrap(value, Data_Type::ruby_data_type()); } else { throw create_type_exception(value); } } } namespace Rice::detail { template class To_Ruby { public: VALUE convert(T& data) { // Get the ruby typeinfo std::pair rubyTypeInfo = detail::Registries::instance.types.figureType(data); // We always take ownership of data passed by value (yes the parameter is T& but the template // matched thus we have to tell wrap to copy the reference we are sending to it return detail::wrap(rubyTypeInfo.first, rubyTypeInfo.second, data, true); } VALUE convert(const T& data) { // Get the ruby typeinfo std::pair rubyTypeInfo = detail::Registries::instance.types.figureType(data); // We always take ownership of data passed by value (yes the parameter is T& but the template // matched thus we have to tell wrap to copy the reference we are sending to it return detail::wrap(rubyTypeInfo.first, rubyTypeInfo.second, data, true); } }; template class To_Ruby { public: To_Ruby() = default; explicit To_Ruby(Return * returnInfo) : returnInfo_(returnInfo) { } VALUE convert(T& data) { // Note that T could be a pointer or reference to a base class while data is in fact a // child class. Lookup the correct type so we return an instance of the correct Ruby class std::pair rubyTypeInfo = detail::Registries::instance.types.figureType(data); bool isOwner = this->returnInfo_ && this->returnInfo_->isOwner(); return detail::wrap(rubyTypeInfo.first, rubyTypeInfo.second, data, isOwner); } VALUE convert(const T& data) { // Note that T could be a pointer or reference to a base class while data is in fact a // child class. Lookup the correct type so we return an instance of the correct Ruby class std::pair rubyTypeInfo = detail::Registries::instance.types.figureType(data); bool isOwner = this->returnInfo_ && this->returnInfo_->isOwner(); return detail::wrap(rubyTypeInfo.first, rubyTypeInfo.second, data, isOwner); } private: Return* returnInfo_ = nullptr; }; template class To_Ruby { public: To_Ruby() = default; explicit To_Ruby(Return* returnInfo) : returnInfo_(returnInfo) { } VALUE convert(T* data) { if (data) { // Note that T could be a pointer or reference to a base class while data is in fact a // child class. Lookup the correct type so we return an instance of the correct Ruby class std::pair rubyTypeInfo = detail::Registries::instance.types.figureType(*data); bool isOwner = this->returnInfo_ && this->returnInfo_->isOwner(); return detail::wrap(rubyTypeInfo.first, rubyTypeInfo.second, data, isOwner); } else { return Qnil; } } VALUE convert(const T* data) { if (data) { // Note that T could be a pointer or reference to a base class while data is in fact a // child class. Lookup the correct type so we return an instance of the correct Ruby class std::pair rubyTypeInfo = detail::Registries::instance.types.figureType(*data); bool isOwner = this->returnInfo_ && this->returnInfo_->isOwner(); return detail::wrap(rubyTypeInfo.first, rubyTypeInfo.second, data, isOwner); } else { return Qnil; } } private: Return* returnInfo_ = nullptr; }; template class To_Ruby { public: To_Ruby() = default; explicit To_Ruby(Return* returnInfo) : returnInfo_(returnInfo) { } VALUE convert(T* data) { if (data) { // Note that T could be a pointer or reference to a base class while data is in fact a // child class. Lookup the correct type so we return an instance of the correct Ruby class std::pair rubyTypeInfo = detail::Registries::instance.types.figureType(*data); bool isOwner = this->returnInfo_ && this->returnInfo_->isOwner(); return detail::wrap(rubyTypeInfo.first, rubyTypeInfo.second, data, isOwner); } else { return Qnil; } } VALUE convert(const T* data) { if (data) { // Note that T could be a pointer or reference to a base class while data is in fact a // child class. Lookup the correct type so we return an instance of the correct Ruby class std::pair rubyTypeInfo = detail::Registries::instance.types.figureType(*data); bool isOwner = this->returnInfo_ && this->returnInfo_->isOwner(); return detail::wrap(rubyTypeInfo.first, rubyTypeInfo.second, data, isOwner); } else { return Qnil; } } private: Return* returnInfo_ = nullptr; }; template class To_Ruby> { public: VALUE convert(const Object& x) { return x.value(); } }; template class From_Ruby { static_assert(!std::is_fundamental_v>, "Data_Object cannot be used with fundamental types"); public: From_Ruby() = default; explicit From_Ruby(Arg * arg) : arg_(arg) { } bool is_convertible(VALUE value) { return rb_type(value) == RUBY_T_DATA && Data_Type::is_descendant(value); } T convert(VALUE value) { using Intrinsic_T = intrinsic_type; if (value == Qnil && this->arg_ && this->arg_->hasDefaultValue()) { return this->arg_->template defaultValue(); } else { return *Data_Object::from_ruby(value); } } private: Arg* arg_ = nullptr; }; template class From_Ruby { static_assert(!std::is_fundamental_v>, "Data_Object cannot be used with fundamental types"); public: From_Ruby() = default; explicit From_Ruby(Arg * arg) : arg_(arg) { } bool is_convertible(VALUE value) { return rb_type(value) == RUBY_T_DATA && Data_Type::is_descendant(value); } T& convert(VALUE value) { using Intrinsic_T = intrinsic_type; if (value == Qnil && this->arg_ && this->arg_->hasDefaultValue()) { return this->arg_->template defaultValue(); } else { return *Data_Object::from_ruby(value); } } private: Arg* arg_ = nullptr; }; template class From_Ruby { static_assert(!std::is_fundamental_v>, "Data_Object cannot be used with fundamental types"); public: bool is_convertible(VALUE value) { return rb_type(value) == RUBY_T_DATA && Data_Type::is_descendant(value); } T* convert(VALUE value) { using Intrinsic_T = intrinsic_type; if (value == Qnil) { return nullptr; } else { return Data_Object::from_ruby(value); } } }; template class From_Ruby { static_assert(!std::is_fundamental_v>, "Data_Object cannot be used with fundamental types"); public: bool is_convertible(VALUE value) { return rb_type(value) == RUBY_T_DATA && Data_Type::is_descendant(value); } T* convert(VALUE value) { using Intrinsic_T = intrinsic_type; if (value == Qnil) { return nullptr; } else { return Data_Object::from_ruby(value); } } }; template class From_Ruby> { static_assert(!std::is_fundamental_v>, "Data_Object cannot be used with fundamental types"); public: static Data_Object convert(VALUE value) { return Data_Object(value); } }; } #endif // Rice__Data_Object__ipp_