static PyObject *bpy_bmlayercollection_items(BPy_BMLayerCollection *self)
{
	PyObject *ret;
	PyObject *item;
	int index;
	CustomData *data;
	int tot, i;

	BPY_BM_CHECK_OBJ(self);

	data = bpy_bm_customdata_get(self->bm, self->htype);
	index = CustomData_get_layer_index(data, self->type);
	tot = (index != -1) ? CustomData_number_of_layers(data, self->type) : 0;

	ret = PyList_New(tot);

	for (i = 0; tot-- > 0; index++) {
		item = PyTuple_New(2);
		PyTuple_SET_ITEMS(item,
		        PyUnicode_FromString(data->layers[index].name),
		        BPy_BMLayerItem_CreatePyObject(self->bm, self->htype, self->type, i));
		PyList_SET_ITEM(ret, i++, item);
	}

	return ret;
}
static PyObject *bpy_bmlayercollection_new(BPy_BMLayerCollection *self, PyObject *args)
{
	const char *name = NULL;
	int index;
	CustomData *data;

	BPY_BM_CHECK_OBJ(self);

	if (!PyArg_ParseTuple(args, "|s:new", &name)) {
		return NULL;
	}

	data = bpy_bm_customdata_get(self->bm, self->htype);

	if (CustomData_layertype_is_singleton(self->type) &&
	    CustomData_has_layer(data, self->type))
	{
		PyErr_SetString(PyExc_ValueError,
		                "layers.new(): is a singleton, use verify() instead");
		return NULL;
	}

	if (name) {
		BM_data_layer_add_named(self->bm, data, self->type, name);
	}
	else {
		BM_data_layer_add(self->bm, data, self->type);
	}

	index = CustomData_number_of_layers(data, self->type) - 1;
	BLI_assert(index >= 0);

	return BPy_BMLayerItem_CreatePyObject(self->bm, self->htype, self->type, index);
}
static PyObject *bpy_bmlayercollection_remove(BPy_BMLayerCollection *self, BPy_BMLayerItem *value)
{
	CustomData *data;

	BPY_BM_CHECK_OBJ(self);

	if (!BPy_BMLayerItem_Check(value)) {
		PyErr_Format(PyExc_TypeError,
		             "layers.remove(x): expected BMLayerItem, not '%.200s'",
		             Py_TYPE(value)->tp_name);
		return NULL;
	}

	BPY_BM_CHECK_OBJ(value);

	if ((self->bm != value->bm) ||
	    (self->type != value->type) ||
	    (self->htype != value->htype))
	{
		PyErr_SetString(PyExc_ValueError,
		                "layers.remove(x): x not in layers");
	}

	data = bpy_bm_customdata_get(self->bm, self->htype);
	BM_data_layer_free_n(self->bm, data, self->type, value->index);

	Py_RETURN_NONE;
}
static PyObject *bpy_bmlayercollection_get(BPy_BMLayerCollection *self, PyObject *args)
{
	const char *key;
	PyObject *def = Py_None;

	BPY_BM_CHECK_OBJ(self);

	if (!PyArg_ParseTuple(args, "s|O:get", &key, &def)) {
		return NULL;
	}
	else {
		CustomData *data;
		int index;

		data = bpy_bm_customdata_get(self->bm, self->htype);
		index = CustomData_get_named_layer_index(data, self->type, key); /* absolute index */

		if (index != -1) {
			index -= CustomData_get_layer_index(data, self->type); /* make relative */
			return BPy_BMLayerItem_CreatePyObject(self->bm, self->htype, self->type, index);
		}
	}

	return Py_INCREF(def), def;
}
static PyObject *bpy_bmlayercollection_items(BPy_BMLayerCollection *self)
{
	PyObject *ret;
	PyObject *item;
	int index;
	CustomData *data;

	BPY_BM_CHECK_OBJ(self);

	data = bpy_bm_customdata_get(self->bm, self->htype);
	index = CustomData_get_layer_index(data, self->type);

	ret = PyList_New(0);

	if (index != -1) {
		int tot = CustomData_number_of_layers(data, self->type);
		for ( ; tot-- > 0; index++) {
			item = BPy_BMLayerItem_CreatePyObject(self->bm, self->htype, self->type, index);
			PyList_Append(ret, item);
			Py_DECREF(item);
		}
	}

	return ret;
}
static PyObject *bpy_bmlayercollection_values(BPy_BMLayerCollection *self)
{
	PyObject *ret;
	PyObject *item;
	int index;
	CustomData *data;

	BPY_BM_CHECK_OBJ(self);

	data = bpy_bm_customdata_get(self->bm, self->htype);
	index = CustomData_get_layer_index(data, self->type);

	ret = PyList_New(0);

	if (index != -1) {
		int tot = CustomData_number_of_layers(data, self->type);
		for ( ; tot-- > 0; index++) {
			item = PyTuple_New(2);
			PyTuple_SET_ITEM(item, 0, PyUnicode_FromString(data->layers[index].name));
			PyTuple_SET_ITEM(item, 1, BPy_BMLayerItem_CreatePyObject(self->bm, self->htype, self->type, index));
			PyList_Append(ret, item);
			Py_DECREF(item);
		}
	}

	return ret;
}
static PyObject *bpy_bmlayercollection_keys(BPy_BMLayerCollection *self)
{
	PyObject *ret;
	PyObject *item;
	int index;
	CustomData *data;

	BPY_BM_CHECK_OBJ(self);

	data = bpy_bm_customdata_get(self->bm, self->htype);
	index = CustomData_get_layer_index(data, self->type); /* absolute, but no need to make relative */

	ret = PyList_New(0);

	if (index != -1) {
		int tot = CustomData_number_of_layers(data, self->type);
		for ( ; tot-- > 0; index++) {
			item = PyUnicode_FromString(data->layers[index].name);
			PyList_Append(ret, item);
			Py_DECREF(item);
		}
	}

	return ret;
}
static Py_ssize_t bpy_bmlayercollection_length(BPy_BMLayerCollection *self)
{
	CustomData *data;

	BPY_BM_CHECK_INT(self);

	data = bpy_bm_customdata_get(self->bm, self->htype);

	return CustomData_number_of_layers(data, self->type);
}
static CustomDataLayer *bpy_bmlayeritem_get(BPy_BMLayerItem *self)
{
	CustomData *data = bpy_bm_customdata_get(self->bm, self->htype);
	const int index_absolute = CustomData_get_layer_index_n(data, self->type, self->index);
	if (index_absolute != -1) {
		return &data->layers[index_absolute];
	}
	else {
		PyErr_SetString(PyExc_RuntimeError,
		                "layer has become invalid");
		return NULL;
	}
}
static PyObject *bpy_bmlayercollection_active_get(BPy_BMLayerItem *self, void *UNUSED(flag))
{
	CustomData *data;
	int index;

	BPY_BM_CHECK_OBJ(self);

	data = bpy_bm_customdata_get(self->bm, self->htype);
	index = CustomData_get_active_layer(data, self->type);  /* type relative */

	if (index != -1) {
		return BPy_BMLayerItem_CreatePyObject(self->bm, self->htype, self->type, index);
	}
	else {
		Py_RETURN_NONE;
	}
}
static int bpy_bmlayercollection_contains(BPy_BMLayerCollection *self, PyObject *value)
{
	const char *keyname = _PyUnicode_AsString(value);
	CustomData *data;
	int index;

	BPY_BM_CHECK_INT(self);

	if (keyname == NULL) {
		PyErr_SetString(PyExc_TypeError,
		                "BMLayerCollection.__contains__: expected a string");
		return -1;
	}

	data = bpy_bm_customdata_get(self->bm, self->htype);
	index = CustomData_get_named_layer_index(data, self->type, keyname);

	return (index != -1) ? 1 : 0;
}
static PyObject *bpy_bmlayercollection_subscript_str(BPy_BMLayerCollection *self, const char *keyname)
{
	CustomData *data;
	int index;

	BPY_BM_CHECK_OBJ(self);

	data = bpy_bm_customdata_get(self->bm, self->htype);
	index = CustomData_get_named_layer(data, self->type, keyname);  /* type relative */

	if (index != -1) {
		return BPy_BMLayerItem_CreatePyObject(self->bm, self->htype, self->type, index);
	}
	else {
		PyErr_Format(PyExc_KeyError,
		             "BMLayerCollection[key]: key \"%.200s\" not found", keyname);
		return NULL;
	}
}
static PyObject *bpy_bmlayercollection_verify(BPy_BMLayerCollection *self)
{
	int index;
	CustomData *data;

	BPY_BM_CHECK_OBJ(self);

	data = bpy_bm_customdata_get(self->bm, self->htype);

	index = CustomData_get_active_layer(data, self->type);  /* type relative */

	if (index == -1) {
		BM_data_layer_add(self->bm, data, self->type);
		index = 0;
	}

	BLI_assert(index >= 0);

	return BPy_BMLayerItem_CreatePyObject(self->bm, self->htype, self->type, index);
}
/**
 * helper function for get/set, NULL return means the error is set
 */
static void *bpy_bmlayeritem_ptr_get(BPy_BMElem *py_ele, BPy_BMLayerItem *py_layer)
{
	void *value;
	BMElem *ele = py_ele->ele;
	CustomData *data;

	/* error checking */
	if (UNLIKELY(!BPy_BMLayerItem_Check(py_layer))) {
		PyErr_SetString(PyExc_AttributeError,
		                "BMElem[key]: invalid key, must be a BMLayerItem");
		return NULL;
	}
	else if (UNLIKELY(py_ele->bm != py_layer->bm)) {
		PyErr_SetString(PyExc_ValueError,
		                "BMElem[layer]: layer is from another mesh");
		return NULL;
	}
	else if (UNLIKELY(ele->head.htype != py_layer->htype)) {
		char namestr_1[32], namestr_2[32];
		PyErr_Format(PyExc_ValueError,
		             "Layer/Element type mismatch, expected %.200s got layer type %.200s",
		             BPy_BMElem_StringFromHType_ex(ele->head.htype, namestr_1),
		             BPy_BMElem_StringFromHType_ex(py_layer->htype, namestr_2));
		return NULL;
	}

	data = bpy_bm_customdata_get(py_layer->bm, py_layer->htype);

	value = CustomData_bmesh_get_n(data, ele->head.data, py_layer->type, py_layer->index);

	if (UNLIKELY(value == NULL)) {
		/* this should be fairly unlikely but possible if layers move about after we get them */
		PyErr_SetString(PyExc_KeyError,
		                "BMElem[key]: layer not found");
		return NULL;
	}
	else {
		return value;
	}
}
static PyObject *bpy_bmlayercollection_values(BPy_BMLayerCollection *self)
{
	PyObject *ret;
	PyObject *item;
	int index;
	CustomData *data;
	int tot, i;

	BPY_BM_CHECK_OBJ(self);

	data = bpy_bm_customdata_get(self->bm, self->htype);
	index = CustomData_get_layer_index(data, self->type);
	tot = (index != -1) ? CustomData_number_of_layers(data, self->type) : 0;

	ret = PyList_New(tot);

	for (i = 0; tot-- > 0; index++) {
		item = BPy_BMLayerItem_CreatePyObject(self->bm, self->htype, self->type, i);
		PyList_SET_ITEM(ret, i++, item);
	}

	return ret;
}
static PyObject *bpy_bmlayeritem_copy_from(BPy_BMLayerItem *self, BPy_BMLayerItem *value)
{
	CustomData *data;

	if (!BPy_BMLayerItem_Check(value)) {
		PyErr_Format(PyExc_TypeError,
		             "layer.copy_from(x): expected BMLayerItem, not '%.200s'",
		             Py_TYPE(value)->tp_name);
		return NULL;
	}

	BPY_BM_CHECK_OBJ(self);
	BPY_BM_CHECK_SOURCE_OBJ(self->bm, "layer.copy_from()", value);

	if ((self->htype != value->htype) ||
	    (self->type  != value->type))
	{
		PyErr_SetString(PyExc_ValueError,
		                "layer.copy_from(other): layer type mismatch");
	}

	else if (self->index == value->index) {
		Py_RETURN_NONE;
	}

	data = bpy_bm_customdata_get(self->bm, self->htype);

	if ((bpy_bmlayeritem_get(self) == NULL) ||
	    (bpy_bmlayeritem_get(value) == NULL))
	{
		return NULL;
	}

	BM_data_layer_copy(self->bm, data, self->type, value->index, self->index);

	Py_RETURN_NONE;
}