lucy_Doc* LUCY_Doc_Load_IMP(lucy_Doc *self, cfish_Obj *dump) { dTHX; cfish_Hash *source = (cfish_Hash*)CFISH_CERTIFY(dump, CFISH_HASH); cfish_String *class_name = (cfish_String*)CFISH_CERTIFY( CFISH_Hash_Fetch_Utf8(source, "_class", 6), CFISH_STRING); cfish_Class *klass = cfish_Class_singleton(class_name, NULL); lucy_Doc *loaded = (lucy_Doc*)CFISH_Class_Make_Obj(klass); cfish_Obj *doc_id = CFISH_CERTIFY( CFISH_Hash_Fetch_Utf8(source, "doc_id", 7), CFISH_OBJ); cfish_Hash *fields = (cfish_Hash*)CFISH_CERTIFY( CFISH_Hash_Fetch_Utf8(source, "fields", 6), CFISH_HASH); SV *fields_sv = XSBind_cfish_to_perl(aTHX_ (cfish_Obj*)fields); CFISH_UNUSED_VAR(self); lucy_DocIVARS *const loaded_ivars = lucy_Doc_IVARS(loaded); loaded_ivars->doc_id = (int32_t)lucy_Json_obj_to_i64(doc_id); loaded_ivars->fields = SvREFCNT_inc(SvRV(fields_sv)); SvREFCNT_dec(fields_sv); return loaded; }
void LUCY_Doc_Store_IMP(lucy_Doc *self, cfish_String *field, cfish_Obj *value) { dTHX; lucy_DocIVARS *const ivars = lucy_Doc_IVARS(self); const char *key = CFISH_Str_Get_Ptr8(field); size_t key_size = CFISH_Str_Get_Size(field); SV *key_sv = newSVpvn(key, key_size); SV *val_sv = XSBind_cfish_to_perl(aTHX_ value); SvUTF8_on(key_sv); (void)hv_store_ent((HV*)ivars->fields, key_sv, val_sv, 0); // TODO: make this a thread-local instead of creating it every time? SvREFCNT_dec(key_sv); }
// Convert all arguments to Perl and place them on the Perl stack. static CHY_INLINE void SI_push_args(void *vobj, va_list args, uint32_t num_args) { kino_Obj *obj = (kino_Obj*)vobj; SV *invoker; uint32_t i; dSP; uint32_t stack_slots_needed = num_args < 2 ? num_args + 1 : (num_args * 2) + 1; EXTEND(SP, stack_slots_needed); if (Kino_Obj_Is_A(obj, KINO_VTABLE)) { kino_VTable *vtable = (kino_VTable*)obj; // TODO: Creating a new class name SV every time is wasteful. invoker = XSBind_cb_to_sv(Kino_VTable_Get_Name(vtable)); } else { invoker = (SV*)Kino_Obj_To_Host(obj); } ENTER; SAVETMPS; PUSHMARK(SP); PUSHs( sv_2mortal(invoker) ); for (i = 0; i < num_args; i++) { uint32_t arg_type = va_arg(args, uint32_t); char *label = va_arg(args, char*); if (num_args > 1) { PUSHs( sv_2mortal( newSVpvn(label, strlen(label)) ) ); } switch (arg_type & CFISH_HOST_ARGTYPE_MASK) { case CFISH_HOST_ARGTYPE_I32: { int32_t value = va_arg(args, int32_t); PUSHs( sv_2mortal( newSViv(value) ) ); } break; case CFISH_HOST_ARGTYPE_I64: { int64_t value = va_arg(args, int64_t); if (sizeof(IV) == 8) { PUSHs( sv_2mortal( newSViv((IV)value) ) ); } else { // lossy PUSHs( sv_2mortal( newSVnv((double)value) ) ); } } break; case CFISH_HOST_ARGTYPE_F32: case CFISH_HOST_ARGTYPE_F64: { // Floats are promoted to doubles by variadic calling. double value = va_arg(args, double); PUSHs( sv_2mortal( newSVnv(value) ) ); } break; case CFISH_HOST_ARGTYPE_STR: { kino_CharBuf *string = va_arg(args, kino_CharBuf*); PUSHs( sv_2mortal( XSBind_cb_to_sv(string) ) ); } break; case CFISH_HOST_ARGTYPE_OBJ: { kino_Obj* anObj = va_arg(args, kino_Obj*); SV *arg_sv = anObj == NULL ? newSV(0) : XSBind_cfish_to_perl(anObj); PUSHs( sv_2mortal(arg_sv) ); } break; default: CFISH_THROW(KINO_ERR, "Unrecognized arg type: %u32", arg_type); } } PUTBACK; }