/** @file ObjectConverter.cpp * * @author Roland Conybeare, Nov 2025 **/ #include "ObjectConverter.hpp" #include "Integer.hpp" #include "Float.hpp" #include "Boolean.hpp" #include "String.hpp" #include "TaggedPtr.hpp" #include "xo/alloc/Blob.hpp" namespace xo { using xo::reflect::Reflect; using xo::reflect::TaggedPtr; using xo::reflect::TypeId; using xo::gc::IAlloc; namespace obj { namespace { template gp int_to_object(IAlloc * mm, const TaggedPtr & src) { T * native = src.recover_native(); assert(native); return Integer::make(mm, *native); } template TaggedPtr object_to_int(IAlloc * mm, gp obj) { /* mm cannot be GC allocator! * That's Object-only */ gp int_obj = Integer::from(obj); if (!int_obj.get()) { throw std::runtime_error(tostr("Object obj found where Integer expected", xtag("obj", obj))); } /* allocate a Blob wrapper to satsify GC memory layout demands */ gp tmp = Blob::make(mm, sizeof(T)); T * p = reinterpret_cast(tmp->data()); *p = int_obj->value(); /* WARNING: retval invalidated when *mm cleared/recycled/collected */ return Reflect::make_tp(p); } template gp float_to_object(IAlloc * mm, const TaggedPtr & src) { T * native = src.recover_native(); assert(native); return Float::make(mm, *native); } template TaggedPtr object_to_float(IAlloc * mm, gp obj) { /* mm cannot be GC allocator! * That's Object-only */ gp float_obj = Float::from(obj); if (!float_obj.get()) { throw std::runtime_error(tostr("Object obj found where Float expected", xtag("obj", obj))); } /* allocate a Blob wrapper to satsify GC memory layout demands */ gp tmp = Blob::make(mm, sizeof(T)); T * p = reinterpret_cast(tmp->data()); *p = float_obj->value(); /* WARNING: retval invalidated when *mm cleared/recycled/collected */ return Reflect::make_tp(p); } gp bool_to_object(IAlloc * /*mm*/, const TaggedPtr & src) { bool * native = src.recover_native(); assert(native); return Boolean::boolean_obj(*native); } TaggedPtr object_to_bool(IAlloc * /*mm*/, gp obj) { static bool s_true = true; static bool s_false = false; gp bool_obj = Boolean::from(obj); if (!bool_obj.get()) { throw std::runtime_error(tostr("Object obj found where Boolean expected", xtag("obj", obj))); } return Reflect::make_tp(bool_obj->value() ? &s_true : &s_false); } gp string_to_object(IAlloc * mm, const TaggedPtr & src) { std::string * native = src.recover_native(); assert(native); return String::copy(mm, native->c_str()); } TaggedPtr object_to_string(IAlloc * /*mm*/, gp obj) { gp string_obj = String::from(obj); if (!string_obj.get()) { throw std::runtime_error(tostr("Object obj founcd where String expected", xtag("obj", obj))); } // still don't have good solver for this yet assert(false); } } ObjectConverter::ObjectConverter() { this->establish_conversion(&int_to_object, &object_to_int); this->establish_conversion(&int_to_object, &object_to_int); this->establish_conversion(&float_to_object, &object_to_float); this->establish_conversion(&bool_to_object, &object_to_bool); this->establish_conversion(&string_to_object, &object_to_string); } gp ObjectConverter::tp_to_object(IAlloc * mm, const TaggedPtr & x_tp, bool throw_flag) { using xo::reflect::Reflect; using xo::reflect::TaggedPtr; const Converter * cvt = cvt_.lookup(x_tp.td()); if (cvt) { return (cvt->cvt_to_object_)(mm, x_tp); } else { if (throw_flag) { throw std::runtime_error (tostr("no to-object-converter available for instance of type", xtag("id", x_tp.td()->id()), xtag("name", x_tp.td()->short_name()))); } return nullptr; } } TaggedPtr ObjectConverter::tp_from_object(IAlloc * mm, gp & obj, TypeId target_id, bool throw_flag) { const Converter * cvt = cvt_.lookup(target_id); if (cvt) { return (cvt->cvt_from_object_)(mm, obj); } else { if (throw_flag) { throw std::runtime_error(tostr("no from-object-converter available for instance of type", xtag("id", target_id))); } return TaggedPtr::universal_null(); } } } } /* end ObjectConverter.cpp */