Skip to content

Commit 8ecb065

Browse files
authored
Go Encode/Decode fixes (#1865)
This PR does a couple things. 1. Adds some cffi roundtripping tests for go 2. Uses those tests to make sure that classes encode/decode properly 3. Uses those tests to make sure that map[string]primitive and []primitive work if they are return values or input parameters 4. Remove passing the typeMap recursively since its statically available inside the baml code (you will notice the type signature is the only change) 5. Added `BamlTypeName()` to the `BamlSerializer` class which allows us to get a baml type name from classes/unions/enums. 6. Use that to support classes as values in maps Still needs a test with a Union for map/list
1 parent 4afe910 commit 8ecb065

24 files changed

Lines changed: 2136 additions & 1300 deletions

File tree

engine/language_client_cffi/Makefile.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ dependencies = ["cbindgen"]
2424

2525
[tasks.build-local]
2626
script = '''
27-
python build.py --targets aarch64-apple-darwin --debug
27+
cargo build
2828
'''
2929
dependencies = ["cbindgen"]
3030

engine/language_client_cffi/src/cffi/cffi_generated.rs

Lines changed: 36 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1493,7 +1493,8 @@ impl<'a> flatbuffers::Follow<'a> for CFFIValueList<'a> {
14931493
}
14941494

14951495
impl<'a> CFFIValueList<'a> {
1496-
pub const VT_VALUES: flatbuffers::VOffsetT = 4;
1496+
pub const VT_FIELD_TYPE: flatbuffers::VOffsetT = 4;
1497+
pub const VT_VALUES: flatbuffers::VOffsetT = 6;
14971498

14981499
#[inline]
14991500
pub unsafe fn init_from_table(table: flatbuffers::Table<'a>) -> Self {
@@ -1506,10 +1507,18 @@ impl<'a> CFFIValueList<'a> {
15061507
) -> flatbuffers::WIPOffset<CFFIValueList<'bldr>> {
15071508
let mut builder = CFFIValueListBuilder::new(_fbb);
15081509
if let Some(x) = args.values { builder.add_values(x); }
1510+
if let Some(x) = args.field_type { builder.add_field_type(x); }
15091511
builder.finish()
15101512
}
15111513

15121514

1515+
#[inline]
1516+
pub fn field_type(&self) -> Option<CFFIFieldTypeHolder<'a>> {
1517+
// Safety:
1518+
// Created from valid Table for this object
1519+
// which contains a valid value in this slot
1520+
unsafe { self._tab.get::<flatbuffers::ForwardsUOffset<CFFIFieldTypeHolder>>(CFFIValueList::VT_FIELD_TYPE, None)}
1521+
}
15131522
#[inline]
15141523
pub fn values(&self) -> Option<flatbuffers::Vector<'a, flatbuffers::ForwardsUOffset<CFFIValueHolder<'a>>>> {
15151524
// Safety:
@@ -1526,18 +1535,21 @@ impl flatbuffers::Verifiable for CFFIValueList<'_> {
15261535
) -> Result<(), flatbuffers::InvalidFlatbuffer> {
15271536
use self::flatbuffers::Verifiable;
15281537
v.visit_table(pos)?
1538+
.visit_field::<flatbuffers::ForwardsUOffset<CFFIFieldTypeHolder>>("field_type", Self::VT_FIELD_TYPE, false)?
15291539
.visit_field::<flatbuffers::ForwardsUOffset<flatbuffers::Vector<'_, flatbuffers::ForwardsUOffset<CFFIValueHolder>>>>("values", Self::VT_VALUES, false)?
15301540
.finish();
15311541
Ok(())
15321542
}
15331543
}
15341544
pub struct CFFIValueListArgs<'a> {
1545+
pub field_type: Option<flatbuffers::WIPOffset<CFFIFieldTypeHolder<'a>>>,
15351546
pub values: Option<flatbuffers::WIPOffset<flatbuffers::Vector<'a, flatbuffers::ForwardsUOffset<CFFIValueHolder<'a>>>>>,
15361547
}
15371548
impl<'a> Default for CFFIValueListArgs<'a> {
15381549
#[inline]
15391550
fn default() -> Self {
15401551
CFFIValueListArgs {
1552+
field_type: None,
15411553
values: None,
15421554
}
15431555
}
@@ -1548,6 +1560,10 @@ pub struct CFFIValueListBuilder<'a: 'b, 'b> {
15481560
start_: flatbuffers::WIPOffset<flatbuffers::TableUnfinishedWIPOffset>,
15491561
}
15501562
impl<'a: 'b, 'b> CFFIValueListBuilder<'a, 'b> {
1563+
#[inline]
1564+
pub fn add_field_type(&mut self, field_type: flatbuffers::WIPOffset<CFFIFieldTypeHolder<'b >>) {
1565+
self.fbb_.push_slot_always::<flatbuffers::WIPOffset<CFFIFieldTypeHolder>>(CFFIValueList::VT_FIELD_TYPE, field_type);
1566+
}
15511567
#[inline]
15521568
pub fn add_values(&mut self, values: flatbuffers::WIPOffset<flatbuffers::Vector<'b , flatbuffers::ForwardsUOffset<CFFIValueHolder<'b >>>>) {
15531569
self.fbb_.push_slot_always::<flatbuffers::WIPOffset<_>>(CFFIValueList::VT_VALUES, values);
@@ -1570,6 +1586,7 @@ impl<'a: 'b, 'b> CFFIValueListBuilder<'a, 'b> {
15701586
impl core::fmt::Debug for CFFIValueList<'_> {
15711587
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
15721588
let mut ds = f.debug_struct("CFFIValueList");
1589+
ds.field("field_type", &self.field_type());
15731590
ds.field("values", &self.values());
15741591
ds.finish()
15751592
}
@@ -1704,7 +1721,8 @@ impl<'a> flatbuffers::Follow<'a> for CFFIValueMap<'a> {
17041721
}
17051722

17061723
impl<'a> CFFIValueMap<'a> {
1707-
pub const VT_ENTRIES: flatbuffers::VOffsetT = 4;
1724+
pub const VT_FIELD_TYPES: flatbuffers::VOffsetT = 4;
1725+
pub const VT_ENTRIES: flatbuffers::VOffsetT = 6;
17081726

17091727
#[inline]
17101728
pub unsafe fn init_from_table(table: flatbuffers::Table<'a>) -> Self {
@@ -1717,10 +1735,18 @@ impl<'a> CFFIValueMap<'a> {
17171735
) -> flatbuffers::WIPOffset<CFFIValueMap<'bldr>> {
17181736
let mut builder = CFFIValueMapBuilder::new(_fbb);
17191737
if let Some(x) = args.entries { builder.add_entries(x); }
1738+
if let Some(x) = args.field_types { builder.add_field_types(x); }
17201739
builder.finish()
17211740
}
17221741

17231742

1743+
#[inline]
1744+
pub fn field_types(&self) -> Option<CFFIFieldTypeHolder<'a>> {
1745+
// Safety:
1746+
// Created from valid Table for this object
1747+
// which contains a valid value in this slot
1748+
unsafe { self._tab.get::<flatbuffers::ForwardsUOffset<CFFIFieldTypeHolder>>(CFFIValueMap::VT_FIELD_TYPES, None)}
1749+
}
17241750
#[inline]
17251751
pub fn entries(&self) -> Option<flatbuffers::Vector<'a, flatbuffers::ForwardsUOffset<CFFIMapEntry<'a>>>> {
17261752
// Safety:
@@ -1737,18 +1763,21 @@ impl flatbuffers::Verifiable for CFFIValueMap<'_> {
17371763
) -> Result<(), flatbuffers::InvalidFlatbuffer> {
17381764
use self::flatbuffers::Verifiable;
17391765
v.visit_table(pos)?
1766+
.visit_field::<flatbuffers::ForwardsUOffset<CFFIFieldTypeHolder>>("field_types", Self::VT_FIELD_TYPES, false)?
17401767
.visit_field::<flatbuffers::ForwardsUOffset<flatbuffers::Vector<'_, flatbuffers::ForwardsUOffset<CFFIMapEntry>>>>("entries", Self::VT_ENTRIES, false)?
17411768
.finish();
17421769
Ok(())
17431770
}
17441771
}
17451772
pub struct CFFIValueMapArgs<'a> {
1773+
pub field_types: Option<flatbuffers::WIPOffset<CFFIFieldTypeHolder<'a>>>,
17461774
pub entries: Option<flatbuffers::WIPOffset<flatbuffers::Vector<'a, flatbuffers::ForwardsUOffset<CFFIMapEntry<'a>>>>>,
17471775
}
17481776
impl<'a> Default for CFFIValueMapArgs<'a> {
17491777
#[inline]
17501778
fn default() -> Self {
17511779
CFFIValueMapArgs {
1780+
field_types: None,
17521781
entries: None,
17531782
}
17541783
}
@@ -1759,6 +1788,10 @@ pub struct CFFIValueMapBuilder<'a: 'b, 'b> {
17591788
start_: flatbuffers::WIPOffset<flatbuffers::TableUnfinishedWIPOffset>,
17601789
}
17611790
impl<'a: 'b, 'b> CFFIValueMapBuilder<'a, 'b> {
1791+
#[inline]
1792+
pub fn add_field_types(&mut self, field_types: flatbuffers::WIPOffset<CFFIFieldTypeHolder<'b >>) {
1793+
self.fbb_.push_slot_always::<flatbuffers::WIPOffset<CFFIFieldTypeHolder>>(CFFIValueMap::VT_FIELD_TYPES, field_types);
1794+
}
17621795
#[inline]
17631796
pub fn add_entries(&mut self, entries: flatbuffers::WIPOffset<flatbuffers::Vector<'b , flatbuffers::ForwardsUOffset<CFFIMapEntry<'b >>>>) {
17641797
self.fbb_.push_slot_always::<flatbuffers::WIPOffset<_>>(CFFIValueMap::VT_ENTRIES, entries);
@@ -1781,6 +1814,7 @@ impl<'a: 'b, 'b> CFFIValueMapBuilder<'a, 'b> {
17811814
impl core::fmt::Debug for CFFIValueMap<'_> {
17821815
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
17831816
let mut ds = f.debug_struct("CFFIValueMap");
1817+
ds.field("field_types", &self.field_types());
17841818
ds.field("entries", &self.entries());
17851819
ds.finish()
17861820
}

engine/language_client_cffi/src/ctypes.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -277,9 +277,12 @@ where
277277

278278
let values = builder.create_vector_from_iter(items.into_iter());
279279

280+
let field_type = field_type_to_cffi_value_holder(value.field_type(), &mut builder);
281+
280282
let value_list = CFFIValueList::create(
281283
&mut builder,
282284
&CFFIValueListArgs {
285+
field_type: Some(field_type),
283286
values: Some(values),
284287
},
285288
);
@@ -303,9 +306,12 @@ where
303306

304307
let entries = builder.create_vector_from_iter(items.into_iter());
305308

309+
let field_types = field_type_to_cffi_value_holder(value.field_type(), &mut builder);
310+
306311
let value_map = CFFIValueMap::create(
307312
&mut builder,
308313
&CFFIValueMapArgs {
314+
field_types: Some(field_types),
309315
entries: Some(entries),
310316
},
311317
);

engine/language_client_cffi/types/cffi.fbs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ table CFFIValueBool {
4444
}
4545

4646
table CFFIValueList {
47+
field_type: CFFIFieldTypeHolder;
4748
values: [CFFIValueHolder];
4849
}
4950

@@ -54,6 +55,7 @@ table CFFIMapEntry {
5455
}
5556

5657
table CFFIValueMap {
58+
field_types: CFFIFieldTypeHolder;
5759
entries: [CFFIMapEntry];
5860
}
5961

engine/language_client_codegen/src/go/generate_types.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ pub(crate) fn cast_value(container_variable_name: &str, field_type: &GoType) ->
5656
fn render_value_coercion(container_variable_name: &str, field_type: &GoType) -> String {
5757
if field_type.is_class {
5858
return format!(
59-
"*baml.Decode({}, typeMap).(*{})",
59+
"*baml.Decode({}).(*{})",
6060
container_variable_name,
6161
filters::type_name_without_pointer(&field_type.name)
6262
.ok()
@@ -65,20 +65,20 @@ fn render_value_coercion(container_variable_name: &str, field_type: &GoType) ->
6565
} else if field_type.is_slice {
6666
let inner_type = field_type.underlying_type.as_ref().unwrap();
6767
return format!(
68-
r#"baml.DecodeList({container_variable_name}, typeMap, func(__holder *cffi.CFFIValueHolder, typeMap baml.TypeMap) {} {{
68+
r#"baml.DecodeList({container_variable_name}, func(__holder *cffi.CFFIValueHolder) {} {{
6969
return {}
7070
}})"#,
7171
inner_type.name,
7272
render_value_coercion("__holder", inner_type),
7373
);
7474
} else if field_type.is_union {
7575
return format!(
76-
"*baml.Decode({container_variable_name}, typeMap).(*{})",
76+
"*baml.Decode({container_variable_name}).(*{})",
7777
field_type.name
7878
);
7979
} else {
8080
return format!(
81-
"baml.Decode({container_variable_name}, typeMap).({})",
81+
"baml.Decode({container_variable_name}).({})",
8282
field_type.name
8383
);
8484
}

engine/language_client_codegen/src/go/templates/client.go.j2

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ func {{ fn.name }}(ctx context.Context{% for (name, type) in fn.args -%}
5252
, {{name}} {{type}}
5353
{%- endfor %}) (*{{ fn.return_type }}, error) {
5454
args := map[string]any{ {% for (name, type) in fn.args -%}"{{name}}": {{name}},{% endfor %} }
55-
encoded, err := baml.EncodeRoot(args, typeMap)
55+
encoded, err := baml.EncodeRoot(args)
5656
if err != nil {
5757
panic(err)
5858
}
@@ -78,7 +78,7 @@ func (*stream) {{ fn.name }}(ctx context.Context{% for (name, type) in fn.args -
7878
, {{name}} {{type}}
7979
{%- endfor %}) <-chan {{ fn.return_type }} {
8080
args := map[string]any{ {% for (name, type) in fn.args -%}"{{name}}": {{name}},{% endfor %} }
81-
encoded, err := baml.EncodeRoot(args, typeMap)
81+
encoded, err := baml.EncodeRoot(args)
8282
if err != nil {
8383
panic(err)
8484
}

engine/language_client_codegen/src/go/templates/inlinedbaml.go.j2

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,4 +8,4 @@ var file_map = map[string]string{
88

99
func getBamlFiles() map[string]string {
1010
return file_map
11-
}
11+
}

engine/language_client_codegen/src/go/templates/types-enums.go.j2

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -74,15 +74,19 @@ func (e *{{ enum.name }}) UnmarshalJSON(data []byte) error {
7474
return nil
7575
}
7676

77-
func (e *{{ enum.name }}) Decode(holder cffi.CFFIValueEnum, typeMap baml.TypeMap) {
77+
func (e *{{ enum.name }}) Decode(holder cffi.CFFIValueEnum) {
7878
if string(holder.Name()) != "{{ enum.name }}" {
7979
panic(fmt.Sprintf("expected {{ enum.name }}, got %s", string(holder.Name())))
8080
}
8181
value := string(holder.Value())
8282
*e = {{ enum.name }}(value)
8383
}
8484

85-
func (e {{ enum.name }}) Encode(builder *flatbuffers.Builder, typeMap baml.TypeMap) (cffi.CFFIValueUnion, flatbuffers.UOffsetT, error) {
85+
func (e {{ enum.name }}) Encode(builder *flatbuffers.Builder) (cffi.CFFIValueUnion, flatbuffers.UOffsetT, error) {
8686
return baml.EncodeEnum(builder, "{{ enum.name }}", string(e), false)
8787
}
88+
89+
func (e {{ enum.name }}) BamlTypeName() string {
90+
return "{{ enum.name }}"
91+
}
8892
{% endfor %}

engine/language_client_codegen/src/go/templates/types-unions.go.j2

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ type {{ union.name }} struct {
1717
{% endfor %}
1818
}
1919

20-
func (u *{{ union.name }}) Decode(holder *cffi.CFFIValueUnionVariant, typeMap baml.TypeMap) {
20+
func (u *{{ union.name }}) Decode(holder *cffi.CFFIValueUnionVariant) {
2121
valueHolder := holder.Value(nil)
2222
switch holder.ValueTypeIndex() {
2323
{% for variant in union.variants %}
@@ -30,11 +30,11 @@ func (u *{{ union.name }}) Decode(holder *cffi.CFFIValueUnionVariant, typeMap ba
3030
}
3131

3232

33-
func (u {{ union.name }}) Encode(builder *flatbuffers.Builder, typeMap baml.TypeMap) (cffi.CFFIValueUnion, flatbuffers.UOffsetT, error) {
33+
func (u {{ union.name }}) Encode(builder *flatbuffers.Builder) (cffi.CFFIValueUnion, flatbuffers.UOffsetT, error) {
3434
switch u.variant {
3535
{% for variant in union.variants %}
3636
case "{{ variant.0 }}":
37-
return baml.EncodeUnion(builder, typeMap, u.variant, u.variant_{{ variant.0 }})
37+
return baml.EncodeUnion(builder, u.variant, u.variant_{{ variant.0 }})
3838
{% endfor %}
3939
case "":
4040
return cffi.CFFIValueUnionNONE, 0, fmt.Errorf("invalid union variant: [unset]")
@@ -43,6 +43,10 @@ func (u {{ union.name }}) Encode(builder *flatbuffers.Builder, typeMap baml.Type
4343
return cffi.CFFIValueUnionNONE, 0, fmt.Errorf("invalid union variant: %s", u.variant)
4444
}
4545

46+
func (u {{ union.name }}) BamlTypeName() string {
47+
return "{{ union.name }}"
48+
}
49+
4650
{% for variant in union.variants %}
4751
func (u *{{ union.name }}) Set{{ variant.0|exported_name }}(v {{ variant.1.name }}) {
4852
u.variant = "{{ variant.0 }}"

engine/language_client_codegen/src/go/templates/types.go.j2

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ type {{ class.name }} struct {
2727
{% endif %}
2828
}
2929

30-
func (c *{{ class.name }}) Decode(holder cffi.CFFIValueClass, typeMap baml.TypeMap) {
30+
func (c *{{ class.name }}) Decode(holder cffi.CFFIValueClass) {
3131
if string(holder.Name()) != "{{ class.name }}" {
3232
panic(fmt.Sprintf("expected {{ class.name }}, got %s", string(holder.Name())))
3333
}
@@ -55,18 +55,22 @@ func (c *{{ class.name }}) Decode(holder cffi.CFFIValueClass, typeMap baml.TypeM
5555
if holder.DynamicFields(&field, i) {
5656
key := string(field.Key())
5757
valueHolder := field.Value(nil)
58-
c.DynamicProperties[key] = baml.Decode(valueHolder, typeMap)
58+
c.DynamicProperties[key] = baml.Decode(valueHolder)
5959
}
6060
}
6161
{% endif %}
6262
}
6363

64-
func (c {{ class.name }}) Encode(builder *flatbuffers.Builder, typeMap baml.TypeMap) (cffi.CFFIValueUnion, flatbuffers.UOffsetT, error) {
64+
func (c {{ class.name }}) Encode(builder *flatbuffers.Builder) (cffi.CFFIValueUnion, flatbuffers.UOffsetT, error) {
6565
fields := map[string]any{}
6666
{% for field in class.fields %}
6767
fields["{{ field.name }}"] = c.{{ field.name|exported_name }}
6868
{% endfor %}
69-
return baml.EncodeClass(builder, typeMap, "{{ class.name }}", fields, {% if class.dynamic %}&c.DynamicProperties{% else %}nil{% endif %})
69+
return baml.EncodeClass(builder, "{{ class.name }}", fields, {% if class.dynamic %}&c.DynamicProperties{% else %}nil{% endif %})
70+
}
71+
72+
func (c {{ class.name }}) BamlTypeName() string {
73+
return "{{ class.name }}"
7074
}
7175

7276
{% endfor %}

0 commit comments

Comments
 (0)