1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132
|
/* go-convert-interface.c -- convert interfaces for Go.
Copyright 2009 The Go Authors. All rights reserved.
Use of this source code is governed by a BSD-style
license that can be found in the LICENSE file. */
#include "runtime.h"
#include "go-alloc.h"
#include "go-assert.h"
#include "go-panic.h"
#include "go-string.h"
#include "go-type.h"
#include "interface.h"
/* This is called when converting one interface type into another
interface type. LHS_DESCRIPTOR is the type descriptor of the
resulting interface. RHS_DESCRIPTOR is the type descriptor of the
object being converted. This builds and returns a new interface
method table. If any method in the LHS_DESCRIPTOR interface is not
implemented by the object, the conversion fails. If the conversion
fails, then if MAY_FAIL is true this returns NULL; otherwise, it
panics. */
void *
__go_convert_interface_2 (const struct __go_type_descriptor *lhs_descriptor,
const struct __go_type_descriptor *rhs_descriptor,
_Bool may_fail)
{
const struct __go_interface_type *lhs_interface;
int lhs_method_count;
const struct __go_interface_method* lhs_methods;
const void **methods;
const struct __go_uncommon_type *rhs_uncommon;
int rhs_method_count;
const struct __go_method *p_rhs_method;
int i;
if (rhs_descriptor == NULL)
{
/* A nil value always converts to nil. */
return NULL;
}
__go_assert ((lhs_descriptor->__code & GO_CODE_MASK) == GO_INTERFACE);
lhs_interface = (const struct __go_interface_type *) lhs_descriptor;
lhs_method_count = lhs_interface->__methods.__count;
lhs_methods = ((const struct __go_interface_method *)
lhs_interface->__methods.__values);
/* This should not be called for an empty interface. */
__go_assert (lhs_method_count > 0);
rhs_uncommon = rhs_descriptor->__uncommon;
if (rhs_uncommon == NULL || rhs_uncommon->__methods.__count == 0)
{
struct __go_empty_interface panic_arg;
if (may_fail)
return NULL;
runtime_newTypeAssertionError (NULL, rhs_descriptor->__reflection,
lhs_descriptor->__reflection,
lhs_methods[0].__name,
&panic_arg);
__go_panic (panic_arg);
}
rhs_method_count = rhs_uncommon->__methods.__count;
p_rhs_method = ((const struct __go_method *)
rhs_uncommon->__methods.__values);
methods = NULL;
for (i = 0; i < lhs_method_count; ++i)
{
const struct __go_interface_method *p_lhs_method;
p_lhs_method = &lhs_methods[i];
while (rhs_method_count > 0
&& (!__go_ptr_strings_equal (p_lhs_method->__name,
p_rhs_method->__name)
|| !__go_ptr_strings_equal (p_lhs_method->__pkg_path,
p_rhs_method->__pkg_path)))
{
++p_rhs_method;
--rhs_method_count;
}
if (rhs_method_count == 0
|| !__go_type_descriptors_equal (p_lhs_method->__type,
p_rhs_method->__mtype))
{
struct __go_empty_interface panic_arg;
if (methods != NULL)
__go_free (methods);
if (may_fail)
return NULL;
runtime_newTypeAssertionError (NULL, rhs_descriptor->__reflection,
lhs_descriptor->__reflection,
p_lhs_method->__name, &panic_arg);
__go_panic (panic_arg);
}
if (methods == NULL)
{
methods = (const void **) __go_alloc ((lhs_method_count + 1)
* sizeof (void *));
/* The first field in the method table is always the type of
the object. */
methods[0] = rhs_descriptor;
}
methods[i + 1] = p_rhs_method->__function;
}
return methods;
}
/* This is called by the compiler to convert a value from one
interface type to another. */
void *
__go_convert_interface (const struct __go_type_descriptor *lhs_descriptor,
const struct __go_type_descriptor *rhs_descriptor)
{
return __go_convert_interface_2 (lhs_descriptor, rhs_descriptor, 0);
}
|