o
    ٰi                     @  s   d Z ddlmZ ddlZddlmZ ddlmZ ddlm	Z	m
Z
mZmZmZ ddlmZ dd	lmZmZmZmZ d
dlmZ d
dlmZ edZeefd	dd ddZd!ddZdS )"a  Helpers for mirroring registered C++ FFI types with Python dataclass syntax.

The :func:`c_class` decorator is the primary entry point.  It inspects the
reflection metadata that the C++ runtime exposes via the TVM FFI registry and
turns it into Python ``dataclass``-style descriptors: annotated attributes become
properties that forward to the underlying C++ object, while an ``__init__``
method is synthesized to call the FFI constructor when requested.
    )annotationsN)Callable)InitVar)ClassVarTypeTypeVar
get_originget_type_hints)dataclass_transform   )	TypeFieldTypeInfo+_lookup_or_register_type_info_from_type_key_set_type_cls   )_utils)field_InputClsType)field_specifiersTtype_keystrinitboolreturn4Callable[[Type[_InputClsType]], Type[_InputClsType]]c                   s   d fdd}|S )a
  (Experimental) Create a dataclass-like proxy for a C++ class registered with TVM FFI.

    The decorator reads the reflection metadata that was registered on the C++
    side using ``tvm::ffi::reflection::ObjectDef`` and binds it to the annotated
    attributes in the decorated Python class. Each field defined in C++ becomes
    a property on the Python class, and optional default values can be provided
    with :func:`tvm_ffi.dataclasses.field` in the same way as Python's native
    ``dataclasses.field``.

    The intent is to offer a familiar dataclass authoring experience while still
    exposing the underlying C++ object.  The ``type_key`` of the C++ class must
    match the string passed to :func:`c_class`, and inheritance relationships are
    preserved-subclasses registered in C++ can subclass the Python proxy defined
    for their parent.

    Parameters
    ----------
    type_key
        The reflection key that identifies the C++ type in the FFI registry,
        e.g. ``"testing.MyClass"`` as registered in
        ``src/ffi/extra/testing.cc``.

    init
        If ``True`` and the Python class does not define ``__init__``, an
        initializer is auto-generated that mirrors the reflected constructor
        signature.  The generated initializer calls the C++ ``__init__``
        function registered with ``ObjectDef`` and invokes ``__post_init__`` if
        it exists on the Python class.

    Returns
    -------
    Callable[[type], type]
        A class decorator that materializes the final proxy class.

    Examples
    --------
    Register the C++ type and its fields with TVM FFI:

    .. code-block:: c++

        TVM_FFI_STATIC_INIT_BLOCK() {
          namespace refl = tvm::ffi::reflection;
          refl::ObjectDef<MyClass>()
              .def_static("__init__", [](int64_t v_i64, int32_t v_i32,
                                         double v_f64, float v_f32) -> Any {
                   return ObjectRef(ffi::make_object<MyClass>(
                       v_i64, v_i32, v_f64, v_f32));
               })
              .def_rw("v_i64", &MyClass::v_i64)
              .def_rw("v_i32", &MyClass::v_i32)
              .def_rw("v_f64", &MyClass::v_f64)
              .def_rw("v_f32", &MyClass::v_f32);
        }

    Mirror the same structure in Python using dataclass-style annotations:

    .. code-block:: python

        from tvm_ffi.dataclasses import c_class, field


        @c_class("example.MyClass")
        class MyClass:
            v_i64: int
            v_i32: int
            v_f64: float = field(default=0.0)
            v_f32: float = field(default_factory=lambda: 1.0)


        obj = MyClass(v_i64=4, v_i32=8)
        obj.v_f64 = 3.14  # transparently forwards to the underlying C++ object

    super_type_clsType[_InputClsType]r   c                   s~    od| j v t}|jd usJ t| ||_|jD ]}t| | q r,t| |nd }tj|| d|id}t	|| |S )N__init__)	type_infoclsmethods)
__dict__r   parent_type_info_inspect_c_class_fieldsfieldsr   fill_dataclass_fieldmethod_inittype_info_to_clsr   )r   r   
type_fieldfn_inittype_clsr   r    O/home/ubuntu/.local/lib/python3.10/site-packages/tvm_ffi/dataclasses/c_class.py	decoratorx   s   

zc_class.<locals>.decoratorN)r   r   r   r   r,   )r   r   r.   r,   r+   r-   c_class*   s   Nr/   r*   typer   r   list[TypeField]c           	        s   t jdkrt| dd nt|   fddt| di  D } dd |jD }g }| D ]$\}}|dr8q.||d }|d u rMt	d	|  d
| d|
| q.|rlddd | D }t	d|  d| d|S )N)   	   T)include_extrasc                   s*   i | ]}t  | ttfvr| | qS r,   )r   r   r   ).0nametype_hints_resolvedr,   r-   
<dictcomp>   s    
z+_inspect_c_class_fields.<locals>.<dictcomp>__annotations__c                 S  s   i | ]}|j |qS r,   r6   r5   fr,   r,   r-   r9      s    	__tvm_ffizExtraneous field `.z#`. Defined in Python but not in C++z, c                 s  s    | ]
}d |j  d V  qdS )`Nr;   r<   r,   r,   r-   	<genexpr>   s    z*_inspect_c_class_fields.<locals>.<genexpr>zMissing fields in `z`: z". Defined in C++ but not in Python)sysversion_infor	   getattrkeysr$   items
startswithpop
ValueErrorappendjoinvalues)	r*   r   type_hints_pytype_fields_cxxtype_fields
field_name_field_ty_pyr(   extra_fieldsr,   r7   r-   r#      s0   

	
r#   )T)r   r   r   r   r   r   )r*   r0   r   r   r   r1   )__doc__
__future__r   rB   collections.abcr   dataclassesr   typingr   r   r   r   r	   typing_extensionsr
   corer   r   r   r    r   r   r   r/   r#   r,   r,   r,   r-   <module>   s   	
d