Skip to content

Commit d771f30

Browse files
committed
Support struct and table types in Python->Rust type encoding. #19
1 parent 0994ac7 commit d771f30

File tree

1 file changed

+35
-14
lines changed

1 file changed

+35
-14
lines changed

python/cocoindex/typing.py

Lines changed: 35 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import typing
22
import collections
3+
import dataclasses
34
from typing import Annotated, NamedTuple, Any
45

56
class Vector(NamedTuple):
@@ -31,18 +32,38 @@ def _get_origin_type_and_metadata(t):
3132
return (t.__origin__, t.__metadata__)
3233
return (t, ())
3334

34-
def _type_to_json_value(t, metadata):
35+
def _dump_fields_schema(cls: type) -> list[dict[str, Any]]:
36+
return [
37+
{
38+
'name': field.name,
39+
'value_type': _dump_enriched_type(field.type),
40+
}
41+
for field in dataclasses.fields(cls)
42+
]
43+
44+
def _dump_type(t, metadata):
3545
origin_type = typing.get_origin(t)
3646
if origin_type is collections.abc.Sequence or origin_type is list:
37-
dim = _find_annotation(metadata, Vector)
38-
if dim is None:
39-
raise ValueError(f"Vector dimension not found for {t}")
4047
args = typing.get_args(t)
41-
origin_type, metadata = _get_origin_type_and_metadata(args[0])
42-
type_json = {
43-
'kind': 'Vector',
44-
'element_type': _type_to_json_value(origin_type, metadata),
45-
'dimension': dim.dim,
48+
elem_type, elem_type_metadata = _get_origin_type_and_metadata(args[0])
49+
vector_annot = _find_annotation(metadata, Vector)
50+
if vector_annot is not None:
51+
encoded_type = {
52+
'kind': 'Vector',
53+
'element_type': _dump_type(elem_type, elem_type_metadata),
54+
'dimension': vector_annot.dim,
55+
}
56+
elif dataclasses.is_dataclass(elem_type):
57+
encoded_type = {
58+
'kind': 'Table',
59+
'row': _dump_fields_schema(elem_type),
60+
}
61+
else:
62+
raise ValueError(f"Unsupported type: {t}")
63+
elif dataclasses.is_dataclass(t):
64+
encoded_type = {
65+
'kind': 'Struct',
66+
'fields': _dump_fields_schema(t),
4667
}
4768
else:
4869
type_kind = _find_annotation(metadata, TypeKind)
@@ -61,15 +82,15 @@ def _type_to_json_value(t, metadata):
6182
kind = 'Float64'
6283
else:
6384
raise ValueError(f"type unsupported yet: {t}")
64-
type_json = { 'kind': kind }
85+
encoded_type = { 'kind': kind }
6586

66-
return type_json
87+
return encoded_type
6788

68-
def _enriched_type_to_json_value(t) -> dict[str, Any] | None:
89+
def _dump_enriched_type(t) -> dict[str, Any] | None:
6990
if t is None:
7091
return None
7192
t, metadata = _get_origin_type_and_metadata(t)
72-
enriched_type_json = {'type': _type_to_json_value(t, metadata)}
93+
enriched_type_json = {'type': _dump_type(t, metadata)}
7394
attrs = None
7495
for attr in metadata:
7596
if isinstance(attr, TypeAttr):
@@ -85,4 +106,4 @@ def dump_type(t) -> dict[str, Any] | None:
85106
"""
86107
Convert a Python type to a CocoIndex's type in JSON.
87108
"""
88-
return _enriched_type_to_json_value(t)
109+
return _dump_enriched_type(t)

0 commit comments

Comments
 (0)