/** @file GCObjectConversion.hpp * * @author Roland Conybeare, Jan 2026 **/ #pragma once #include #include #include #include #include namespace xo { namespace scm { /** @brief compile-time conversion obj <-> T * * Specialize for each T that participates in conversion. * Methods here aren't implemented **/ template struct GCObjectConversion { using AGCObject = xo::mm::AGCObject; using AAllocator = xo::mm::AAllocator; /** find gc-aware representation for @p x. * If necessary allocate from @p mm, but may * refer to @p x in-place **/ static obj to_gco(obj mm, const T & x); /** convert to native representation @tparam T from gc-aware * @p gco. If necessary allocate from @p mm, but * may instead refer to @p x in-place **/ static T from_gco(obj mm, obj gco); }; /** Motivating use-case for GCObjectConversion is to transform * primitive function arguments and results to/from gc-aware * representation. * * However: Schematika also supports runtime polymorphism * which leads to primitives that expect obj arguments. * * Also, Schematika expression parser needs representation for * expressions, before type unification. * * Consider a function like: * def fact = lambda (n : i64) { if (n <= 0) then 1 else (n * fact(n - 1)); } * During expression parsing the rhs argument to multiply has unknown type. * To construct an expression for input to unification will use polymorphic * binding for multiply primitive, relying on specialization here for * its implementation. **/ template struct GCObjectConversion> { using AGCObject = xo::mm::AGCObject; using AAllocator = xo::mm::AAllocator; using FacetRegistry = xo::facet::FacetRegistry; using DVariantPlaceholder = xo::facet::DVariantPlaceholder; static obj to_gco(obj, obj gco) { if constexpr (std::is_same_v) { // trivial conversion! return gco; } else if constexpr (std::is_same_v) { // runtime polymorphism return FacetRegistry::instance().variant(gco); } else /* DRepr != DVariantPlaceholder */ { // known content w/ fat object pointer return obj(gco.data()); } } static obj from_gco(obj, obj gco) { scope log(XO_DEBUG(false)); if constexpr (std::is_same_v) { // Need accurate handling of DVariantPlaceholder. // runtime type must be some concrete type. // Only use obj::from when DRepr is a concrete type if constexpr (std::is_same_v) { // At comptime gco has unknown repr. At runtime // will have some known repr, which assignment here will transfer return gco; } else { // Runtime conversion to concrete type DRepr auto retval = obj::from(gco); if (!retval) { log.retroactively_enable(); log && log(xtag("gco.tseq", gco._typeseq())); log && log(xtag("DRepr.tseq", reflect::typeseq::id())); } assert(retval); return retval; } } else { // both runtime and comptime polymorphism // use same path here, since representation of @p gco // is type-erased here return FacetRegistry::instance().variant(gco); } } }; } /*namespace scm */ } /*namespace xo*/ /* end GCObjectConversion.hpp */