Repository: Zuzu-Typ/PyGLM (language: python)

Issue:
Constructing vectors from bytes not possible for multi-byte types
Hi,

first of all thanks for this great package! It helped me a lot for my current project already.

I was reading about the buffer protocol compatibility of the GLM types in the wiki and I tried to convert vector types to and from the binary format. Apart from one-byte integer types (uint8, int8), I am unable to construct vectors from bytes:

```python
vector = glm.u8vec3(1, 2, 3)
as_bytes = bytes(vector)
print(glm.u8vec3(as_bytes))  # prints as expected: "u8vec3(            1,            2,            3 )"
```

but
```python
vector = glm.i16vec3(1, 2, 3)
as_bytes = bytes(vector)
print(glm.i16vec3(as_bytes))  # throws: "TypeError: invalid argument type(s) for vec3()"
```

and also
```python
vector = glm.f32vec3(1, 2, 3)
as_bytes = bytes(vector)
print(glm.f32vec3(as_bytes))  # throws: "TypeError: invalid argument type(s) for vec3()"
```

I also tested this with other vector lengths, but got the same error. Am I missing something here or is it simply not possible to do this for multiple bytes? Thanks in advance!


Discussion / hints:
Hi there (: 

You're very welcome!

The reason why it doesn't work is simple, because even the first variant wasn't actually intended. It just happened to be a useful byproduct of the way the buffer protocol works.

In Python, bytes are stored as unsigned characters (i.e. unsigned integers with 8 data bits). That is the same format used by the `u8`-vectors.
Thus, the type check succeeds when a bytes object is passed.

I have contemplated having a `from_bytes` method, but never got around to it. So I guess now would be my call (: 

I'll try to get around to it soon.

Cheers,
--Zuzu_Typ--

Fix patch:
diff --git a/PyGLM.cpp b/PyGLM.cpp
index ab2b1b0..8bea153 100644
--- a/PyGLM.cpp
+++ b/PyGLM.cpp
@@ -22,32 +22,8 @@
 // PyGLM FUNCTIONS
 #include "PyGLM/functions/all.h"
 
-
-//static PyObject*
-//_get_type_info(PyObject*, PyObject* args) {
-//	PyObject *arg1, *arg2;
-//	PyGLM_Arg_Unpack_2O(args, "_get_type_info", arg1, arg2);
-//	PyGLMTypeInfo pti(PyGLM_Number_AsLong(arg1), arg2);
-//	return PyLong_FromLong(pti.info);
-//}
-//
-
-
-
 //static PyObject*
 //test(PyObject*, PyObject* arg) {
-//
-//
-//	uint64 ptr1 = reinterpret_cast<uint64>(&hbvec1Type);
-//	uint64 ptr2 = reinterpret_cast<uint64>(&hbvec1GLMType.typeObject);
-//
-//	PyGLMTypeObject* ptr3 =(&hbvec1GLMType);
-//	PyGLMTypeObject* ptr4 =((PyGLMTypeObject*)(&hbvec1Type));
-//	
-//	//PyGLMTypeInfo pti(PyGLM_T_ALL | PyGLM_SHAPE_ALL | PyGLMTypeInfo::getDT<float>(), arg);
-//	////return pack(*((glm::mat<4,4, float>*)pti.data));
-//	//return PyLong_FromLong(pti.info);
-//	Py_RETURN_FALSE;
 //}
 //#define HAS_TEST
 //#define TEST_FUNC_TYPE METH_O
@@ -386,15 +362,6 @@ extern "C" {
 		if (module_glm == NULL)
 			return NULL;
 
-//#if !(PyGLM_BUILD & PyGLM_NO_FUNCTIONS)
-//		// backwards compatibility
-//		Py_INCREF(module_glm);
-//		PyModule_AddObject(module_glm, "detail", module_glm);
-//
-//		Py_INCREF(module_glm);
-//		PyModule_AddObject(module_glm, "gtc", module_glm);
-//#endif
-
 		// float
 		PyModule_AddObject(module_glm, "c_float", ctypes_float);
 		Py_INCREF(ctypes_float);
diff --git a/PyGLM/internal_functions/type_checkers.h b/PyGLM/internal_functions/type_checkers.h
index 8d79565..ae127ae 100644
--- a/PyGLM/internal_functions/type_checkers.h
+++ b/PyGLM/internal_functions/type_checkers.h
@@ -2195,6 +2195,10 @@ struct PyGLMTypeInfo {
 
 #define	PyGLM_Is_PyGLM_Type(o) (((PyTypeObject*)(o))->tp_dealloc == (destructor)vec_dealloc || ((PyTypeObject*)(o))->tp_dealloc == (destructor)mvec_dealloc || ((PyTypeObject*)(o))->tp_dealloc == (destructor)mat_dealloc || ((PyTypeObject*)(o))->tp_dealloc == (destructor)qua_dealloc)
 
+#define PyGLM_Ctypes_Check(o) (((PyTypeObject*)(o))->tp_dealloc == ctypes_dealloc)
+
+#define PyGLM_Array_Check(o) (((PyTypeObject*)(o)) == &glmArrayType)
+
 //#define PyGLM_VEC_SHAPE_CHECK(o, L) ((((shape_helper*)o)->shape & 0b1111) == L)
 //#define PyGLM_MAT_SHAPE_CHECK(o, C, R) ((((shape_helper*)o)->shape & 0b111) == C && (((shape_helper*)o)->shape >> 3 & 0b111) == R)
 
diff --git a/PyGLM/type_methods/all.h b/PyGLM/type_methods/all.h
index da783b7..50e5d08 100644
--- a/PyGLM/type_methods/all.h
+++ b/PyGLM/type_methods/all.h
@@ -8,4 +8,22 @@
 
 #include "qua.h"
 
-#include "glmArray.h"
\ No newline at end of file
+#include "glmArray.h"
+
+static PyObject*
+generic_to_bytes(PyObject* self, PyObject*) {
+	PyGLMTypeObject* pto = (PyGLMTypeObject*)self->ob_type;
+	return PyBytes_FromStringAndSize(pto->getDataOf(self), pto->itemSize);
+}
+
+static PyObject*
+generic_copy(PyObject* self, PyObject*) {
+	return PyObject_Call((PyObject*)(self->ob_type), PyTuple_Pack(1, self), NULL);
+}
+
+static PyObject*
+generic_deepcopy(PyObject* self, PyObject* memo) {
+	PyObject* copy = generic_copy(self, NULL);
+	PyDict_SetItem(memo, PyLong_FromVoidPtr((void*)self), copy);
+	return copy;
+}
diff --git a/PyGLM/type_methods/glmArray.h b/PyGLM/type_methods/glmArray.h
index c3005ef..83fd784 100644
--- a/PyGLM/type_methods/glmArray.h
+++ b/PyGLM/type_methods/glmArray.h
@@ -6,11 +6,286 @@
 
 #include "../types/glmArray/glmArray.h"
 
+#include "../internal_functions/type_checkers.h"
+
 static PyObject*
 glmArray_getPtr(glmArray* self, void*) {
 	return PyGLM_CtypesVoidP_FromVoidP(self->data);
 }
 
+static PyObject*
+glmArray_to_bytes(glmArray* self, PyObject*) {
+	return PyBytes_FromStringAndSize((char*)self->data, self->nBytes);
+}
+
+static PyObject*
+glmArray_from_bytes(PyObject*, PyObject* args) {
+	PyObject* bytesObj, *typeObj = NULL;
+
+	if (!PyArg_UnpackTuple(args, "from_bytes", 1, 2, &bytesObj, &typeObj)) return NULL;
+
+	if (typeObj == NULL) {
+		typeObj = ctypes_uint8;
+	}
+
+	if (PyBytes_Check(bytesObj) && PyType_Check(typeObj)) {
+		if (PyGLM_Is_PyGLM_Type(typeObj)) {
+			PyGLMTypeObject* pto = (PyGLMTypeObject*)typeObj;
+
+			Py_ssize_t& nBytes = PyBytes_GET_SIZE(bytesObj);
+
+			PyGLM_ASSERT((nBytes > 0 && nBytes % pto->itemSize == 0), "Invalid bytes string length");
+
+			glmArray* out = (glmArray*)glmArrayType.tp_alloc(&glmArrayType, 0);
+
+			if (out == NULL) {
+				PyErr_SetString(PyExc_MemoryError, "Out of memory");
+				return NULL;
+			}
+
+			out->data = reinterpret_cast<void*>(PyBytes_AS_STRING(bytesObj));
+
+			out->dtSize = pto->dtSize;
+
+			out->format = pto->format;
+
+			out->glmType = pto->glmType;
+
+			out->itemSize = pto->itemSize;
+
+			out->nBytes = PyBytes_GET_SIZE(bytesObj);
+
+			out->itemCount = out->nBytes / out->itemSize;
+
+			out->readonly = 0;
+
+			out->reference = PyGLM_INCREF(bytesObj);
+
+			out->subtype = pto->subtype;
+
+			out->setShape(pto->C, pto->R);
+
+			return (PyObject*)out;
+		}
+
+		if (PyGLM_Ctypes_Check(typeObj)) {
+			glmArray* out = (glmArray*)glmArrayType.tp_alloc(&glmArrayType, 0);
+
+			if (out == NULL) {
+				PyErr_SetString(PyExc_MemoryError, "Out of memory");
+				return NULL;
+			}
+
+			out->data = reinterpret_cast<void*>(PyBytes_AS_STRING(bytesObj));
+
+			out->reference = PyGLM_INCREF(bytesObj);
+
+			out->subtype = (PyTypeObject*)typeObj;
+
+			if (typeObj == ctypes_double) {
+				out->dtSize = sizeof(double);
+				out->format = PyGLM_FS_DOUBLE;
+			} 
+			else if (typeObj == ctypes_float) {
+				out->dtSize = sizeof(float);
+				out->format = PyGLM_FS_FLOAT;
+			} 
+			else if (typeObj == ctypes_int64) {
+				out->dtSize = sizeof(int64);
+				out->format = PyGLM_FS_INT64;
+			}
+			else if (typeObj == ctypes_int32) {
+				out->dtSize = sizeof(int32);
+				out->format = PyGLM_FS_INT32;
+			}
+			else if (typeObj == ctypes_int16) {
+				out->dtSize = sizeof(int16);
+				out->format = PyGLM_FS_INT16;
+			}
+			else if (typeObj == ctypes_int8) {
+				out->dtSize = sizeof(int8);
+				out->format = PyGLM_FS_INT8;
+			}
+			else if (typeObj == ctypes_uint64) {
+				out->dtSize = sizeof(uint64);
+				out->format = PyGLM_FS_UINT64;
+			}
+			else if (typeObj == ctypes_uint32) {
+				out->dtSize = sizeof(uint32);
+				out->format = PyGLM_FS_UINT32;
+			}
+			else if (typeObj == ctypes_uint16) {
+				out->dtSize = sizeof(uint16);
+				out->format = PyGLM_FS_UINT16;
+			}
+			else if (typeObj == ctypes_uint8) {
+				out->dtSize = sizeof(uint8);
+				out->format = PyGLM_FS_UINT8;
+			}
+			else if (typeObj == ctypes_bool) {
+				out->dtSize = sizeof(bool);
+				out->format = PyGLM_FS_BOOL;
+			}
+			else {
+				Py_DECREF(out);
+				PyGLM_TYPEERROR_O("from_bytes() expects a GLM or ctypes number type, not ", typeObj);
+				return NULL;
+			}
+
+			out->itemSize = out->dtSize;
+
+			out->glmType = PyGLM_TYPE_CTYPES;
+
+			out->nBytes = PyBytes_GET_SIZE(bytesObj);
+
+			out->itemCount = out->nBytes / out->itemSize;
+
+			out->readonly = 0;
+
+			out->setShape(0);
+
+			if ((out->nBytes == 0 || out->nBytes % out->itemSize != 0)) {
+				Py_DECREF(out);
+				PyErr_SetString(PyExc_AssertionError, "Invalid bytes string length");
+				return NULL;
+			}
+
+			return (PyObject*)out;
+		}
+	}
+	PyGLM_TYPEERROR_2O("from_bytes() expects a bytes string and a GLM or ctypes type, not ", bytesObj, typeObj);
+	return NULL;
+}
+
+static PyObject*
+glmArray_reinterpret_cast(glmArray* self, PyObject* arg) {
+	if (PyType_Check(arg)) {
+		if (PyGLM_Is_PyGLM_Type(arg)) {
+			PyGLMTypeObject* pto = (PyGLMTypeObject*)arg;
+
+			PyGLM_ASSERT((self->nBytes % pto->itemSize == 0), "Invalid bytes string length");
+
+			glmArray* out = (glmArray*)glmArrayType.tp_alloc(&glmArrayType, 0);
+
+			if (out == NULL) {
+				PyErr_SetString(PyExc_MemoryError, "Out of memory");
+				return NULL;
+			}
+
+			out->data = self->data;
+
+			out->dtSize = pto->dtSize;
+
+			out->format = pto->format;
+
+			out->glmType = pto->glmType;
+
+			out->itemSize = pto->itemSize;
+
+			out->nBytes = self->nBytes;
+
+			out->itemCount = out->nBytes / out->itemSize;
+
+			out->readonly = 0;
+
+			out->reference = PyGLM_INCREF(((PyObject*)self));
+
+			out->subtype = pto->subtype;
+
+			out->setShape(pto->C, pto->R);
+
+			return (PyObject*)out;
+		}
+
+		if (PyGLM_Ctypes_Check(arg)) {
+			glmArray* out = (glmArray*)glmArrayType.tp_alloc(&glmArrayType, 0);
+
+			if (out == NULL) {
+				PyErr_SetString(PyExc_MemoryError, "Out of memory");
+				return NULL;
+			}
+
+			out->data = self->data;
+
+			out->reference = PyGLM_INCREF(((PyObject*)self));
+
+			out->subtype = (PyTypeObject*)arg;
+
+			if (arg == ctypes_double) {
+				out->dtSize = sizeof(double);
+				out->format = PyGLM_FS_DOUBLE;
+			}
+			else if (arg == ctypes_float) {
+				out->dtSize = sizeof(float);
+				out->format = PyGLM_FS_FLOAT;
+			}
+			else if (arg == ctypes_int64) {
+				out->dtSize = sizeof(int64);
+				out->format = PyGLM_FS_INT64;
+			}
+			else if (arg == ctypes_int32) {
+				out->dtSize = sizeof(int32);
+				out->format = PyGLM_FS_INT32;
+			}
+			else if (arg == ctypes_int16) {
+				out->dtSize = sizeof(int16);
+				out->format = PyGLM_FS_INT16;
+			}
+			else if (arg == ctypes_int8) {
+				out->dtSize = sizeof(int8);
+				out->format = PyGLM_FS_INT8;
+			}
+			else if (arg == ctypes_uint64) {
+				out->dtSize = sizeof(uint64);
+				out->format = PyGLM_FS_UINT64;
+			}
+			else if (arg == ctypes_uint32) {
+				out->dtSize = sizeof(uint32);
+				out->format = PyGLM_FS_UINT32;
+			}
+			else if (arg == ctypes_uint16) {
+				out->dtSize = sizeof(uint16);
+				out->format = PyGLM_FS_UINT16;
+			}
+			else if (arg == ctypes_uint8) {
+				out->dtSize = sizeof(uint8);
+				out->format = PyGLM_FS_UINT8;
+			}
+			else if (arg == ctypes_bool) {
+				out->dtSize = sizeof(bool);
+				out->format = PyGLM_FS_BOOL;
+			}
+			else {
+				Py_DECREF(out);
+				PyGLM_TYPEERROR_O("reinterpret_cast() expects a GLM or ctypes number type, not ", arg);
+				return NULL;
+			}
+
+			out->itemSize = out->dtSize;
+
+			out->glmType = PyGLM_TYPE_CTYPES;
+
+			out->nBytes = self->nBytes;
+
+			out->itemCount = out->nBytes / out->itemSize;
+
+			out->readonly = 0;
+
+			out->setShape(0);
+
+			if ((out->nBytes == 0 || out->nBytes % out->itemSize != 0)) {
+				Py_DECREF(out);
+				PyErr_SetString(PyExc_AssertionError, "Invalid bytes string length");
+				return NULL;
+			}
+
+			return (PyObject*)out;
+		}
+	}
+	PyGLM_TYPEERROR_O("reinterpret_cast() expects a GLM or ctypes type, not ", arg);
+	return NULL;
+}
+
 static PyObject* 
 glmArray_getDtype(glmArray* self, void*) {
 	switch (self->format) {
@@ -2359,7 +2634,7 @@ glmArray_init(glmArray* self, PyObject* args, PyObject* kwds) {
 	}
 
 	// ctypes
-	if (firstElementType->tp_dealloc == ctypes_dealloc) {
+	if (PyGLM_Ctypes_Check(firstElementType)) {
 		GLM_ARRAY_INIT_IF_IS_CTYPES_TUPLE_OR_LIST(float);
 		GLM_ARRAY_INIT_IF_IS_CTYPES_TUPLE_OR_LIST(double);
 		GLM_ARRAY_INIT_IF_IS_CTYPES_TUPLE_OR_LIST(int8);
@@ -2456,7 +2731,7 @@ glmArray_init(glmArray* self, PyObject* args, PyObject* kwds) {
 	// others
 	if (argCount == 1) {
 		// arrays
-		if (firstElementType == &glmArrayType) {
+		if (PyGLM_Array_Check(firstElementType)) {
 			glmArray* other = (glmArray*)firstElement;
 			if (other == self) {
 				return 0;
@@ -2699,7 +2974,7 @@ glmArray_init(glmArray* self, PyObject* args, PyObject* kwds) {
 			}
 
 			// ctypes
-			if (firstElementType->tp_dealloc == ctypes_dealloc) {
+			if (PyGLM_Ctypes_Check(firstElementType)) {
 				GLM_ARRAY_INIT_IF_IS_CTYPES_ITER(float);
 				GLM_ARRAY_INIT_IF_IS_CTYPES_ITER(double);
 				GLM_ARRAY_INIT_IF_IS_CTYPES_ITER(int8);
diff --git a/PyGLM/type_methods/mat.h b/PyGLM/type_methods/mat.h
index 79bd0ef..8e1435f 100644
--- a/PyGLM/type_methods/mat.h
+++ b/PyGLM/type_methods/mat.h
@@ -2849,6 +2849,20 @@ mat_releasebuffer(PyObject*, Py_buffer* view) {
 	PyMem_Free(view->strides);
 }
 
+template<int C, int R, typename T>
+static PyObject*
+mat_from_bytes(PyObject*, PyObject* arg) {
+	PyTypeObject* type = PyGLM_MAT_TYPE<C, R, T>();
+	if (PyBytes_Check(arg) && PyBytes_GET_SIZE(arg) == ((PyGLMTypeObject*)type)->itemSize) {
+		char* bytesAsString = PyBytes_AS_STRING(arg);
+		mat<C, R, T>* self = (mat<C, R, T> *)type->tp_alloc(type, 0);
+		self->super_type = *(glm::mat<C, R, T>*)bytesAsString;
+		return (PyObject*)self;
+	}
+	PyGLM_TYPEERROR_O("Invalid argument type for from_bytes(). Expected bytes, got ", arg);
+	return NULL;
+}
+
 template<int C, int R, typename T>
 static Py_hash_t
 mat_hash(mat<C, R, T>* self, PyObject*) {
diff --git a/PyGLM/type_methods/qua.h b/PyGLM/type_methods/qua.h
index fd90d75..e336d12 100644
--- a/PyGLM/type_methods/qua.h
+++ b/PyGLM/type_methods/qua.h
@@ -552,6 +552,20 @@ qua_releasebuffer(PyObject*, Py_buffer* view) {
 	PyMem_Free(view->shape);
 }
 
+template<typename T>
+static PyObject*
+qua_from_bytes(PyObject*, PyObject* arg) {
+	PyTypeObject* type = PyGLM_QUA_TYPE<T>();
+	if (PyBytes_Check(arg) && PyBytes_GET_SIZE(arg) == ((PyGLMTypeObject*)type)->itemSize) {
+		char* bytesAsString = PyBytes_AS_STRING(arg);
+		qua<T>* self = (qua<T> *)type->tp_alloc(type, 0);
+		self->super_type = *(glm::qua<T>*)bytesAsString;
+		return (PyObject*)self;
+	}
+	PyGLM_TYPEERROR_O("Invalid argument type for from_bytes(). Expected bytes, got ", arg);
+	return NULL;
+}
+
 template<typename T>
 static Py_hash_t
 qua_hash(qua<T>* self, PyObject*) {
diff --git a/PyGLM/type_methods/vec.h b/PyGLM/type_methods/vec.h
index a2bfc01..5492306 100644
--- a/PyGLM/type_methods/vec.h
+++ b/PyGLM/type_methods/vec.h
@@ -1873,18 +1873,19 @@ vec_releasebuffer(PyObject*, Py_buffer* view) {
 
 
 
-static PyObject*
-generic_copy(PyObject* self, PyObject*) {
-	return PyObject_Call((PyObject*)(self->ob_type), PyTuple_Pack(1, self), NULL);
-}
-
-
 
+template<int L, typename T>
 static PyObject*
-generic_deepcopy(PyObject* self, PyObject* memo) {
-	PyObject* copy = generic_copy(self, NULL);
-	PyDict_SetItem(memo, PyLong_FromVoidPtr((void*)self), copy);
-	return copy;
+vec_from_bytes(PyObject*, PyObject* arg) {
+	PyTypeObject* type = PyGLM_VEC_TYPE<L, T>();
+	if (PyBytes_Check(arg) && PyBytes_GET_SIZE(arg) == ((PyGLMTypeObject*)type)->itemSize) {
+		char* bytesAsString = PyBytes_AS_STRING(arg);
+		vec<L, T>* self = (vec<L, T> *)type->tp_alloc(type, 0);
+		self->super_type = *(glm::vec<L, T>*)bytesAsString;
+		return (PyObject*)self;
+	}
+	PyGLM_TYPEERROR_O("Invalid argument type for from_bytes(). Expected bytes, got ", arg);
+	return NULL;
 }
 
 template<int L, typename T>
diff --git a/PyGLM/types/forward_declarations.h b/PyGLM/types/forward_declarations.h
index 7e3deed..ab65adb 100644
--- a/PyGLM/types/forward_declarations.h
+++ b/PyGLM/types/forward_declarations.h
@@ -12,4 +12,6 @@ PyDoc_STRVAR(generic_deepcopy_docstr,
 	"Create a (deep)copy of this instance"
 );
 
-static PyObject* generic_deepcopy(PyObject* self, PyObject* memo);
\ No newline at end of file
+static PyObject* generic_deepcopy(PyObject* self, PyObject* memo);
+
+static PyObject* generic_to_bytes(PyObject* self, PyObject*);
\ No newline at end of file
diff --git a/PyGLM/types/glmArray/forward_declarations.h b/PyGLM/types/glmArray/forward_declarations.h
index 21aa89f..a5ec0bc 100644
--- a/PyGLM/types/glmArray/forward_declarations.h
+++ b/PyGLM/types/glmArray/forward_declarations.h
@@ -7,6 +7,27 @@ static int glmArray_getbuffer(glmArray* self, Py_buffer* view, int flags);
 
 void glmArray_releasebuffer(PyObject* self, Py_buffer* view);
 
+PyDoc_STRVAR(glmArray_to_bytes_docstr,
+	"Return the data of this array as a bytes string"
+);
+
+static PyObject* glmArray_to_bytes(glmArray* self, PyObject*);
+
+PyDoc_STRVAR(glmArray_from_bytes_docstr,
+	"from_bytes(bytes_object: bytes, type_object: type = uint8) -> array\n"
+	"	Creates an array with the data given by `bytes_object`, using `type_object` as the element type.\n"
+	"	(The resulting array is a reference copy)"
+);
+
+static PyObject* glmArray_from_bytes(PyObject*, PyObject* args);
+
+PyDoc_STRVAR(glmArray_reinterpret_cast_docstr,
+	"reinterpret_cast(type_object: type) -> array\n"
+	"	Creates an array with the same data as this one, using `type_object` as the new element type.\n"
+	"	(The resulting array is a reference copy)"
+);
+
+static PyObject* glmArray_reinterpret_cast(glmArray* self, PyObject* arg);
 
 PyDoc_STRVAR(glmArray_to_list_docstr,
 	"Return the elements of this array as a list"
diff --git a/PyGLM/types/glmArray/glmArray.h b/PyGLM/types/glmArray/glmArray.h
index 87507fe..5f00d36 100644
--- a/PyGLM/types/glmArray/glmArray.h
+++ b/PyGLM/types/glmArray/glmArray.h
@@ -28,6 +28,9 @@ static PyMethodDef glmArray_methods[] = {
 	{ "__deepcopy__",	(PyCFunction)generic_deepcopy,			METH_O,						generic_deepcopy_docstr },
 	{ "__getstate__",	(PyCFunction)glmArray_getstate,			METH_NOARGS,				glmArray_getstate_docstr },
 	{ "__setstate__",	(PyCFunction)glmArray_setstate,			METH_O,						glmArray_setstate_docstr },
+	{ "to_bytes",		(PyCFunction)glmArray_to_bytes,			METH_NOARGS,				glmArray_to_bytes_docstr },
+	{ "from_bytes",		(PyCFunction)glmArray_from_bytes,		METH_VARARGS | METH_STATIC, glmArray_from_bytes_docstr },
+	{ "reinterpret_cast",(PyCFunction)glmArray_reinterpret_cast,METH_O,						glmArray_reinterpret_cast_docstr },
 	{ "to_list",		(PyCFunction)glmArray_to_list,			METH_NOARGS,				glmArray_to_list_docstr },
 	{ "to_tuple",		(PyCFunction)glmArray_to_tuple,			METH_NOARGS,				glmArray_to_tuple_docstr },
 	{ "split_components",(PyCFunction)glmArray_split_components,METH_NOARGS,				glmArray_split_components_docstr },
diff --git a/PyGLM/types/mat/double/mat2x2.h b/PyGLM/types/mat/double/mat2x2.h
index 0d4838c..cf52eab 100644
--- a/PyGLM/types/mat/double/mat2x2.h
+++ b/PyGLM/types/mat/double/mat2x2.h
@@ -10,6 +10,8 @@ static PyMethodDef hdmat2x2_methods[] = {
 	{ "__setstate__", (PyCFunction)mat_setstate<2, 2, double>, METH_O, "Restores a state that was previously acquired"},
 	{ "to_list", (PyCFunction)mat_to_list<2, 2, double>, METH_NOARGS, "Return the components of this matrix as a nested list"},
 	{ "to_tuple", (PyCFunction)mat_to_tuple<2, 2, double>, METH_NOARGS, "Return the components of this matrix as a nested tuple"},
+	{ "to_bytes", (PyCFunction)generic_to_bytes, METH_NOARGS, "Create a bytes string from this object"},
+	{ "from_bytes", (PyCFunction)mat_from_bytes<2, 2, double>, METH_O | METH_STATIC, "Create a matrix from a bytes string"},
 	{ NULL }
 };
 static PyBufferProcs hdmat2x2BufferMethods = {
diff --git a/PyGLM/types/mat/double/mat2x3.h b/PyGLM/types/mat/double/mat2x3.h
index 3f81592..92f5eaa 100644
--- a/PyGLM/types/mat/double/mat2x3.h
+++ b/PyGLM/types/mat/double/mat2x3.h
@@ -10,6 +10,8 @@ static PyMethodDef hdmat2x3_methods[] = {
 	{ "__setstate__", (PyCFunction)mat_setstate<2, 3, double>, METH_O, "Restores a state that was previously acquired"},
 	{ "to_list", (PyCFunction)mat_to_list<2, 3, double>, METH_NOARGS, "Return the components of this matrix as a nested list"},
 	{ "to_tuple", (PyCFunction)mat_to_tuple<2, 3, double>, METH_NOARGS, "Return the components of this matrix as a nested tuple"},
+	{ "to_bytes", (PyCFunction)generic_to_bytes, METH_NOARGS, "Create a bytes string from this object"},
+	{ "from_bytes", (PyCFunction)mat_from_bytes<2, 3, double>, METH_O | METH_STATIC, "Create a matrix from a bytes string"},
 	{ NULL }
 };
 static PyBufferProcs hdmat2x3BufferMethods = {
diff --git a/PyGLM/types/mat/double/mat2x4.h b/PyGLM/types/mat/double/mat2x4.h
index 8585c37..8e99430 100644
--- a/PyGLM/types/mat/double/mat2x4.h
+++ b/PyGLM/types/mat/double/mat2x4.h
@@ -10,6 +10,8 @@ static PyMethodDef hdmat2x4_methods[] = {
 	{ "__setstate__", (PyCFunction)mat_setstate<2, 4, double>, METH_O, "Restores a state that was previously acquired"},
 	{ "to_list", (PyCFunction)mat_to_list<2, 4, double>, METH_NOARGS, "Return the components of this matrix as a nested list"},
 	{ "to_tuple", (PyCFunction)mat_to_tuple<2, 4, double>, METH_NOARGS, "Return the components of this matrix as a nested tuple"},
+	{ "to_bytes", (PyCFunction)generic_to_bytes, METH_NOARGS, "Create a bytes string from this object"},
+	{ "from_bytes", (PyCFunction)mat_from_bytes<2, 4, double>, METH_O | METH_STATIC, "Create a matrix from a bytes string"},
 	{ NULL }
 };
 static PyBufferProcs hdmat2x4BufferMethods = {
diff --git a/PyGLM/types/mat/double/mat3x2.h b/PyGLM/types/mat/double/mat3x2.h
index d70e68b..5946b6a 100644
--- a/PyGLM/types/mat/double/mat3x2.h
+++ b/PyGLM/types/mat/double/mat3x2.h
@@ -10,6 +10,8 @@ static PyMethodDef hdmat3x2_methods[] = {
 	{ "__setstate__", (PyCFunction)mat_setstate<3, 2, double>, METH_O, "Restores a state that was previously acquired"},
 	{ "to_list", (PyCFunction)mat_to_list<3, 2, double>, METH_NOARGS, "Return the components of this matrix as a nested list"},
 	{ "to_tuple", (PyCFunction)mat_to_tuple<3, 2, double>, METH_NOARGS, "Return the components of this matrix as a nested tuple"},
+	{ "to_bytes", (PyCFunction)generic_to_bytes, METH_NOARGS, "Create a bytes string from this object"},
+	{ "from_bytes", (PyCFunction)mat_from_bytes<3, 2, double>, METH_O | METH_STATIC, "Create a matrix from a bytes string"},
 	{ NULL }
 };
 static PyBufferProcs hdmat3x2BufferMethods = {
diff --git a/PyGLM/types/mat/double/mat3x3.h b/PyGLM/types/mat/double/mat3x3.h
index 7b4ec13..479c0b4 100644
--- a/PyGLM/types/mat/double/mat3x3.h
+++ b/PyGLM/types/mat/double/mat3x3.h
@@ -10,6 +10,8 @@ static PyMethodDef hdmat3x3_methods[] = {
 	{ "__setstate__", (PyCFunction)mat_setstate<3, 3, double>, METH_O, "Restores a state that was previously acquired"},
 	{ "to_list", (PyCFunction)mat_to_list<3, 3, double>, METH_NOARGS, "Return the components of this matrix as a nested list"},
 	{ "to_tuple", (PyCFunction)mat_to_tuple<3, 3, double>, METH_NOARGS, "Return the components of this matrix as a nested tuple"},
+	{ "to_bytes", (PyCFunction)generic_to_bytes, METH_NOARGS, "Create a bytes string from this object"},
+	{ "from_bytes", (PyCFunction)mat_from_bytes<3, 3, double>, METH_O | METH_STATIC, "Create a matrix from a bytes string"},
 	{ NULL }
 };
 static PyBufferProcs hdmat3x3BufferMethods = {
diff --git a/PyGLM/types/mat/double/mat3x4.h b/PyGLM/types/mat/double/mat3x4.h
index b2d2359..1fd8fec 100644
--- a/PyGLM/types/mat/double/mat3x4.h
+++ b/PyGLM/types/mat/double/mat3x4.h
@@ -10,6 +10,8 @@ static PyMethodDef hdmat3x4_methods[] = {
 	{ "__setstate__", (PyCFunction)mat_setstate<3, 4, double>, METH_O, "Restores a state that was previously acquired"},
 	{ "to_list", (PyCFunction)mat_to_list<3, 4, double>, METH_NOARGS, "Return the components of this matrix as a nested list"},
 	{ "to_tuple", (PyCFunction)mat_to_tuple<3, 4, double>, METH_NOARGS, "Return the components of this matrix as a nested tuple"},
+	{ "to_bytes", (PyCFunction)generic_to_bytes, METH_NOARGS, "Create a bytes string from this object"},
+	{ "from_bytes", (PyCFunction)mat_from_bytes<3, 4, double>, METH_O | METH_STATIC, "Create a matrix from a bytes string"},
 	{ NULL }
 };
 static PyBufferProcs hdmat3x4BufferMethods = {
diff --git a/PyGLM/types/mat/double/mat4x2.h b/PyGLM/types/mat/double/mat4x2.h
index 09c6d6d..7fa0147 100644
--- a/PyGLM/types/mat/double/mat4x2.h
+++ b/PyGLM/types/mat/double/mat4x2.h
@@ -10,6 +10,8 @@ static PyMethodDef hdmat4x2_methods[] = {
 	{ "__setstate__", (PyCFunction)mat_setstate<4, 2, double>, METH_O, "Restores a state that was previously acquired"},
 	{ "to_list", (PyCFunction)mat_to_list<4, 2, double>, METH_NOARGS, "Return the components of this matrix as a nested list"},
 	{ "to_tuple", (PyCFunction)mat_to_tuple<4, 2, double>, METH_NOARGS, "Return the components of this matrix as a nested tuple"},
+	{ "to_bytes", (PyCFunction)generic_to_bytes, METH_NOARGS, "Create a bytes string from this object"},
+	{ "from_bytes", (PyCFunction)mat_from_bytes<4, 2, double>, METH_O | METH_STATIC, "Create a matrix from a bytes string"},
 	{ NULL }
 };
 static PyBufferProcs hdmat4x2BufferMethods = {
diff --git a/PyGLM/types/mat/double/mat4x3.h b/PyGLM/types/mat/double/mat4x3.h
index 700a406..2b98e42 100644
--- a/PyGLM/types/mat/double/mat4x3.h
+++ b/PyGLM/types/mat/double/mat4x3.h
@@ -10,6 +10,8 @@ static PyMethodDef hdmat4x3_methods[] = {
 	{ "__setstate__", (PyCFunction)mat_setstate<4, 3, double>, METH_O, "Restores a state that was previously acquired"},
 	{ "to_list", (PyCFunction)mat_to_list<4, 3, double>, METH_NOARGS, "Return the components of this matrix as a nested list"},
 	{ "to_tuple", (PyCFunction)mat_to_tuple<4, 3, double>, METH_NOARGS, "Return the components of this matrix as a nested tuple"},
+	{ "to_bytes", (PyCFunction)generic_to_bytes, METH_NOARGS, "Create a bytes string from this object"},
+	{ "from_bytes", (PyCFunction)mat_from_bytes<4, 3, double>, METH_O | METH_STATIC, "Create a matrix from a bytes string"},
 	{ NULL }
 };
 static PyBufferProcs hdmat4x3BufferMethods = {
diff --git a/PyGLM/types/mat/double/mat4x4.h b/PyGLM/types/mat/double/mat4x4.h
index 76caf06..c9946d7 100644
--- a/PyGLM/types/mat/double/mat4x4.h
+++ b/PyGLM/types/mat/double/mat4x4.h
@@ -10,6 +10,8 @@ static PyMethodDef hdmat4x4_methods[] = {
 	{ "__setstate__", (PyCFunction)mat_setstate<4, 4, double>, METH_O, "Restores a state that was previously acquired"},
 	{ "to_list", (PyCFunction)mat_to_list<4, 4, double>, METH_NOARGS, "Return the components of this matrix as a nested list"},
 	{ "to_tuple", (PyCFunction)mat_to_tuple<4, 4, double>, METH_NOARGS, "Return the components of this matrix as a nested tuple"},
+	{ "to_bytes", (PyCFunction)generic_to_bytes, METH_NOARGS, "Create a bytes string from this object"},
+	{ "from_bytes", (PyCFunction)mat_from_bytes<4, 4, double>, METH_O | METH_STATIC, "Create a matrix from a bytes string"},
 	{ NULL }
 };
 static PyBufferProcs hdmat4x4BufferMethods = {
diff --git a/PyGLM/types/mat/float/mat2x2.h b/PyGLM/types/mat/float/mat2x2.h
index a09746e..06c79ad 100644
--- a/PyGLM/types/mat/float/mat2x2.h
+++ b/PyGLM/types/mat/float/mat2x2.h
@@ -10,6 +10,8 @@ static PyMethodDef hfmat2x2_methods[] = {
 	{ "__setstate__", (PyCFunction)mat_setstate<2, 2, float>, METH_O, "Restores a state that was previously acquired"},
 	{ "to_list", (PyCFunction)mat_to_list<2, 2, float>, METH_NOARGS, "Return the components of this matrix as a nested list"},
 	{ "to_tuple", (PyCFunction)mat_to_tuple<2, 2, float>, METH_NOARGS, "Return the components of this matrix as a nested tuple"},
+	{ "to_bytes", (PyCFunction)generic_to_bytes, METH_NOARGS, "Create a bytes string from this object"},
+	{ "from_bytes", (PyCFunction)mat_from_bytes<2, 2, float>, METH_O | METH_STATIC, "Create a matrix from a bytes string"},
 	{ NULL }
 };
 static PyBufferProcs hfmat2x2BufferMethods = {
diff --git a/PyGLM/types/mat/float/mat2x3.h b/PyGLM/types/mat/float/mat2x3.h
index d01cfd2..ae9698e 100644
--- a/PyGLM/types/mat/float/mat2x3.h
+++ b/PyGLM/types/mat/float/mat2x3.h
@@ -10,6 +10,8 @@ static PyMethodDef hfmat2x3_methods[] = {
 	{ "__setstate__", (PyCFunction)mat_setstate<2, 3, float>, METH_O, "Restores a state that was previously acquired"},
 	{ "to_list", (PyCFunction)mat_to_list<2, 3, float>, METH_NOARGS, "Return the components of this matrix as a nested list"},
 	{ "to_tuple", (PyCFunction)mat_to_tuple<2, 3, float>, METH_NOARGS, "Return the components of this matrix as a nested tuple"},
+	{ "to_bytes", (PyCFunction)generic_to_bytes, METH_NOARGS, "Create a bytes string from this object"},
+	{ "from_bytes", (PyCFunction)mat_from_bytes<2, 3, float>, METH_O | METH_STATIC, "Create a matrix from a bytes string"},
 	{ NULL }
 };
 static PyBufferProcs hfmat2x3BufferMethods = {
diff --git a/PyGLM/types/mat/float/mat2x4.h b/PyGLM/types/mat/float/mat2x4.h
index 902503a..3a5e885 100644
--- a/PyGLM/types/mat/float/mat2x4.h
+++ b/PyGLM/types/mat/float/mat2x4.h
@@ -10,6 +10,8 @@ static PyMethodDef hfmat2x4_methods[] = {
 	{ "__setstate__", (PyCFunction)mat_setstate<2, 4, float>, METH_O, "Restores a state that was previously acquired"},
 	{ "to_list", (PyCFunction)mat_to_list<2, 4, float>, METH_NOARGS, "Return the components of this matrix as a nested list"},
 	{ "to_tuple", (PyCFunction)mat_to_tuple<2, 4, float>, METH_NOARGS, "Return the components of this matrix as a nested tuple"},
+	{ "to_bytes", (PyCFunction)generic_to_bytes, METH_NOARGS, "Create a bytes string from this object"},
+	{ "from_bytes", (PyCFunction)mat_from_bytes<2, 4, float>, METH_O | METH_STATIC, "Create a matrix from a bytes string"},
 	{ NULL }
 };
 static PyBufferProcs hfmat2x4BufferMethods = {
diff --git a/PyGLM/types/mat/float/mat3x2.h b/PyGLM/types/mat/float/mat3x2.h
index 883c980..c946b46 100644
--- a/PyGLM/types/mat/float/mat3x2.h
+++ b/PyGLM/types/mat/float/mat3x2.h
@@ -10,6 +10,8 @@ static PyMethodDef hfmat3x2_methods[] = {
 	{ "__setstate__", (PyCFunction)mat_setstate<3, 2, float>, METH_O, "Restores a state that was previously acquired"},
 	{ "to_list", (PyCFunction)mat_to_list<3, 2, float>, METH_NOARGS, "Return the components of this matrix as a nested list"},
 	{ "to_tuple", (PyCFunction)mat_to_tuple<3, 2, float>, METH_NOARGS, "Return the components of this matrix as a nested tuple"},
+	{ "to_bytes", (PyCFunction)generic_to_bytes, METH_NOARGS, "Create a bytes string from this object"},
+	{ "from_bytes", (PyCFunction)mat_from_bytes<3, 2, float>, METH_O | METH_STATIC, "Create a matrix from a bytes string"},
 	{ NULL }
 };
 static PyBufferProcs hfmat3x2BufferMethods = {
diff --git a/PyGLM/types/mat/float/mat3x3.h b/PyGLM/types/mat/float/mat3x3.h
index 5c4c0d1..756091b 100644
--- a/PyGLM/types/mat/float/mat3x3.h
+++ b/PyGLM/types/mat/float/mat3x3.h
@@ -10,6 +10,8 @@ static PyMethodDef hfmat3x3_methods[] = {
 	{ "__setstate__", (PyCFunction)mat_setstate<3, 3, float>, METH_O, "Restores a state that was previously acquired"},
 	{ "to_list", (PyCFunction)mat_to_list<3, 3, float>, METH_NOARGS, "Return the components of this matrix as a nested list"},
 	{ "to_tuple", (PyCFunction)mat_to_tuple<3, 3, float>, METH_NOARGS, "Return the components of this matrix as a nested tuple"},
+	{ "to_bytes", (PyCFunction)generic_to_bytes, METH_NOARGS, "Create a bytes string from this object"},
+	{ "from_bytes", (PyCFunction)mat_from_bytes<3, 3, float>, METH_O | METH_STATIC, "Create a matrix from a bytes string"},
 	{ NULL }
 };
 static PyBufferProcs hfmat3x3BufferMethods = {
diff --git a/PyGLM/types/mat/float/mat3x4.h b/PyGLM/types/mat/float/mat3x4.h
index fa61900..af405e3 100644
--- a/PyGLM/types/mat/float/mat3x4.h
+++ b/PyGLM/types/mat/float/mat3x4.h
@@ -10,6 +10,8 @@ static PyMethodDef hfmat3x4_methods[] = {
 	{ "__setstate__", (PyCFunction)mat_setstate<3, 4, float>, METH_O, "Restores a state that was previously acquired"},
 	{ "to_list", (PyCFunction)mat_to_list<3, 4, float>, METH_NOARGS, "Return the components of this matrix as a nested list"},
 	{ "to_tuple", (PyCFunction)mat_to_tuple<3, 4, float>, METH_NOARGS, "Return the components of this matrix as a nested tuple"},
+	{ "to_bytes", (PyCFunction)generic_to_bytes, METH_NOARGS, "Create a bytes string from this object"},
+	{ "from_bytes", (PyCFunction)mat_from_bytes<3, 4, float>, METH_O | METH_STATIC, "Create a matrix from a bytes string"},
 	{ NULL }
 };
 static PyBufferProcs hfmat3x4BufferMethods = {
diff --git a/PyGLM/types/mat/float/mat4x2.h b/PyGLM/types/mat/float/mat4x2.h
index 8e04889..41890a2 100644
--- a/PyGLM/types/mat/float/mat4x2.h
+++ b/PyGLM/types/mat/float/mat4x2.h
@@ -10,6 +10,8 @@ static PyMethodDef hfmat4x2_methods[] = {
 	{ "__setstate__", (PyCFunction)mat_setstate<4, 2, float>, METH_O, "Restores a state that was previously acquired"},
 	{ "to_list", (PyCFunction)mat_to_list<4, 2, float>, METH_NOARGS, "Return the components of this matrix as a nested list"},
 	{ "to_tuple", (PyCFunction)mat_to_tuple<4, 2, float>, METH_NOARGS, "Return the components of this matrix as a nested tuple"},
+	{ "to_bytes", (PyCFunction)generic_to_bytes, METH_NOARGS, "Create a bytes string from this object"},
+	{ "from_bytes", (PyCFunction)mat_from_bytes<4, 2, float>, METH_O | METH_STATIC, "Create a matrix from a bytes string"},
 	{ NULL }
 };
 static PyBufferProcs hfmat4x2BufferMethods = {
diff --git a/PyGLM/types/mat/float/mat4x3.h b/PyGLM/types/mat/float/mat4x3.h
index 1affc34..95e8542 100644
--- a/PyGLM/types/mat/float/mat4x3.h
+++ b/PyGLM/types/mat/float/mat4x3.h
@@ -10,6 +10,8 @@ static PyMethodDef hfmat4x3_methods[] = {
 	{ "__setstate__", (PyCFunction)mat_setstate<4, 3, float>, METH_O, "Restores a state that was previously acquired"},
 	{ "to_list", (PyCFunction)mat_to_list<4, 3, float>, METH_NOARGS, "Return the components of this matrix as a nested list"},
 	{ "to_tuple", (PyCFunction)mat_to_tuple<4, 3, float>, METH_NOARGS, "Return the components of this matrix as a nested tuple"},
+	{ "to_bytes", (PyCFunction)generic_to_bytes, METH_NOARGS, "Create a bytes string from this object"},
+	{ "from_bytes", (PyCFunction)mat_from_bytes<4, 3, float>, METH_O | METH_STATIC, "Create a matrix from a bytes string"},
 	{ NULL }
 };
 static PyBufferProcs hfmat4x3BufferMethods = {
diff --git a/PyGLM/types/mat/float/mat4x4.h b/PyGLM/types/mat/float/mat4x4.h
index a5acd3f..3dabdab 100644
--- a/PyGLM/types/mat/float/mat4x4.h
+++ b/PyGLM/types/mat/float/mat4x4.h
@@ -10,6 +10,8 @@ static PyMethodDef hfmat4x4_methods[] = {
 	{ "__setstate__", (PyCFunction)mat_setstate<4, 4, float>, METH_O, "Restores a state that was previously acquired"},
 	{ "to_list", (PyCFunction)mat_to_list<4, 4, float>, METH_NOARGS, "Return the components of this matrix as a nested list"},
 	{ "to_tuple", (PyCFunction)mat_to_tuple<4, 4, float>, METH_NOARGS, "Return the components of this matrix as a nested tuple"},
+	{ "to_bytes", (PyCFunction)generic_to_bytes, METH_NOARGS, "Create a bytes string from this object"},
+	{ "from_bytes", (PyCFunction)mat_from_bytes<4, 4, float>, METH_O | METH_STATIC, "Create a matrix from a bytes string"},
 	{ NULL }
 };
 static PyBufferProcs hfmat4x4BufferMethods = {
diff --git a/PyGLM/types/mat/forward_declarations.h b/PyGLM/types/mat/forward_declarations.h
index 4115026..f759d7e 100644
--- a/PyGLM/types/mat/forward_declarations.h
+++ b/PyGLM/types/mat/forward_declarations.h
@@ -187,6 +187,9 @@ static PyObject* matIter_next(matIter<C, R, T> *rgstate);
 template<int C, int R, typename T>
 static PyObject* matIter_new(PyTypeObject *type, PyObject *args, PyObject *kwargs);
 
+template<int C, int R, typename T>
+static PyObject* mat_from_bytes(PyObject*, PyObject* arg);
+
 template<int C, int R, typename T>
 static Py_hash_t mat_hash(mat<C, R, T>* self, PyObject*);
 
diff --git a/PyGLM/types/mat/int/mat2x2.h b/PyGLM/types/mat/int/mat2x2.h
index f2b654a..1109ee5 100644
--- a/PyGLM/types/mat/int/mat2x2.h
+++ b/PyGLM/types/mat/int/mat2x2.h
@@ -10,6 +10,8 @@ static PyMethodDef himat2x2_methods[] = {
 	{ "__setstate__", (PyCFunction)mat_setstate<2, 2, glm::i32>, METH_O, "Restores a state that was previously acquired"},
 	{ "to_list", (PyCFunction)mat_to_list<2, 2, glm::i32>, METH_NOARGS, "Return the components of this matrix as a nested list"},
 	{ "to_tuple", (PyCFunction)mat_to_tuple<2, 2, glm::i32>, METH_NOARGS, "Return the components of this matrix as a nested tuple"},
+	{ "to_bytes", (PyCFunction)generic_to_bytes, METH_NOARGS, "Create a bytes string from this object"},
+	{ "from_bytes", (PyCFunction)mat_from_bytes<2, 2, glm::i32>, METH_O | METH_STATIC, "Create a matrix from a bytes string"},
 	{ NULL }
 };
 static PyBufferProcs himat2x2BufferMethods = {
diff --git a/PyGLM/types/mat/int/mat2x3.h b/PyGLM/types/mat/int/mat2x3.h
index 569d630..638ae0e 100644
--- a/PyGLM/types/mat/int/mat2x3.h
+++ b/PyGLM/types/mat/int/mat2x3.h
@@ -10,6 +10,8 @@ static PyMethodDef himat2x3_methods[] = {
 	{ "__setstate__", (PyCFunction)mat_setstate<2, 3, glm::i32>, METH_O, "Restores a state that was previously acquired"},
 	{ "to_list", (PyCFunction)mat_to_list<2, 3, glm::i32>, METH_NOARGS, "Return the components of this matrix as a nested list"},
 	{ "to_tuple", (PyCFunction)mat_to_tuple<2, 3, glm::i32>, METH_NOARGS, "Return the components of this matrix as a nested tuple"},
+	{ "to_bytes", (PyCFunction)generic_to_bytes, METH_NOARGS, "Create a bytes string from this object"},
+	{ "from_bytes", (PyCFunction)mat_from_bytes<2, 3, glm::i32>, METH_O | METH_STATIC, "Create a matrix from a bytes string"},
 	{ NULL }
 };
 static PyBufferProcs himat2x3BufferMethods = {
diff --git a/PyGLM/types/mat/int/mat2x4.h b/PyGLM/types/mat/int/mat2x4.h
index d397e8b..2c8b806 100644
--- a/PyGLM/types/mat/int/mat2x4.h
+++ b/PyGLM/types/mat/int/mat2x4.h
@@ -10,6 +10,8 @@ static PyMethodDef himat2x4_methods[] = {
 	{ "__setstate__", (PyCFunction)mat_setstate<2, 4, glm::i32>, METH_O, "Restores a state that was previously acquired"},
 	{ "to_list", (PyCFunction)mat_to_list<2, 4, glm::i32>, METH_NOARGS, "Return the components of this matrix as a nested list"},
 	{ "to_tuple", (PyCFunction)mat_to_tuple<2, 4, glm::i32>, METH_NOARGS, "Return the components of this matrix as a nested tuple"},
+	{ "to_bytes", (PyCFunction)generic_to_bytes, METH_NOARGS, "Create a bytes string from this object"},
+	{ "from_bytes", (PyCFunction)mat_from_bytes<2, 4, glm::i32>, METH_O | METH_STATIC, "Create a matrix from a bytes string"},
 	{ NULL }
 };
 static PyBufferProcs himat2x4BufferMethods = {
diff --git a/PyGLM/types/mat/int/mat3x2.h b/PyGLM/types/mat/int/mat3x2.h
index ae99092..d291332 100644
--- a/PyGLM/types/mat/int/mat3x2.h
+++ b/PyGLM/types/mat/int/mat3x2.h
@@ -10,6 +10,8 @@ static PyMethodDef himat3x2_methods[] = {
 	{ "__setstate__", (PyCFunction)mat_setstate<3, 2, glm::i32>, METH_O, "Restores a state that was previously acquired"},
 	{ "to_list", (PyCFunction)mat_to_list<3, 2, glm::i32>, METH_NOARGS, "Return the components of this matrix as a nested list"},
 	{ "to_tuple", (PyCFunction)mat_to_tuple<3, 2, glm::i32>, METH_NOARGS, "Return the components of this matrix as a nested tuple"},
+	{ "to_bytes", (PyCFunction)generic_to_bytes, METH_NOARGS, "Create a bytes string from this object"},
+	{ "from_bytes", (PyCFunction)mat_from_bytes<3, 2, glm::i32>, METH_O | METH_STATIC, "Create a matrix from a bytes string"},
 	{ NULL }
 };
 static PyBufferProcs himat3x2BufferMethods = {
diff --git a/PyGLM/types/mat/int/mat3x3.h b/PyGLM/types/mat/int/mat3x3.h
index 073282e..c56ab73 100644
--- a/PyGLM/types/mat/int/mat3x3.h
+++ b/PyGLM/types/mat/int/mat3x3.h
@@ -10,6 +10,8 @@ static PyMethodDef himat3x3_methods[] = {
 	{ "__setstate__", (PyCFunction)mat_setstate<3, 3, glm::i32>, METH_O, "Restores a state that was previously acquired"},
 	{ "to_list", (PyCFunction)mat_to_list<3, 3, glm::i32>, METH_NOARGS, "Return the components of this matrix as a nested list"},
 	{ "to_tuple", (PyCFunction)mat_to_tuple<3, 3, glm::i32>, METH_NOARGS, "Return the components of this matrix as a nested tuple"},
+	{ "to_bytes", (PyCFunction)generic_to_bytes, METH_NOARGS, "Create a bytes string from this object"},
+	{ "from_bytes", (PyCFunction)mat_from_bytes<3, 3, glm::i32>, METH_O | METH_STATIC, "Create a matrix from a bytes string"},
 	{ NULL }
 };
 static PyBufferProcs himat3x3BufferMethods = {
diff --git a/PyGLM/types/mat/int/mat3x4.h b/PyGLM/types/mat/int/mat3x4.h
index 383046c..3b17580 100644
--- a/PyGLM/types/mat/int/mat3x4.h
+++ b/PyGLM/types/mat/int/mat3x4.h
@@ -10,6 +10,8 @@ static PyMethodDef himat3x4_methods[] = {
 	{ "__setstate__", (PyCFunction)mat_setstate<3, 4, glm::i32>, METH_O, "Restores a state that was previously acquired"},
 	{ "to_list", (PyCFunction)mat_to_list<3, 4, glm::i32>, METH_NOARGS, "Return the components of this matrix as a nested list"},
 	{ "to_tuple", (PyCFunction)mat_to_tuple<3, 4, glm::i32>, METH_NOARGS, "Return the components of this matrix as a nested tuple"},
+	{ "to_bytes", (PyCFunction)generic_to_bytes, METH_NOARGS, "Create a bytes string from this object"},
+	{ "from_bytes", (PyCFunction)mat_from_bytes<3, 4, glm::i32>, METH_O | METH_STATIC, "Create a matrix from a bytes string"},
 	{ NULL }
 };
 static PyBufferProcs himat3x4BufferMethods = {
diff --git a/PyGLM/types/mat/int/mat4x2.h b/PyGLM/types/mat/int/mat4x2.h
index a7df0b9..99eb5d8 100644
--- a/PyGLM/types/mat/int/mat4x2.h
+++ b/PyGLM/types/mat/int/mat4x2.h
@@ -10,6 +10,8 @@ static PyMethodDef himat4x2_methods[] = {
 	{ "__setstate__", (PyCFunction)mat_setstate<4, 2, glm::i32>, METH_O, "Restores a state that was previously acquired"},
 	{ "to_list", (PyCFunction)mat_to_list<4, 2, glm::i32>, METH_NOARGS, "Return the components of this matrix as a nested list"},
 	{ "to_tuple", (PyCFunction)mat_to_tuple<4, 2, glm::i32>, METH_NOARGS, "Return the components of this matrix as a nested tuple"},
+	{ "to_bytes", (PyCFunction)generic_to_bytes, METH_NOARGS, "Create a bytes string from this object"},
+	{ "from_bytes", (PyCFunction)mat_from_bytes<4, 2, glm::i32>, METH_O | METH_STATIC, "Create a matrix from a bytes string"},
 	{ NULL }
 };
 static PyBufferProcs himat4x2BufferMethods = {
diff --git a/PyGLM/types/mat/int/mat4x3.h b/PyGLM/types/mat/int/mat4x3.h
index 488be3b..c22525d 100644
--- a/PyGLM/types/mat/int/mat4x3.h
+++ b/PyGLM/types/mat/int/mat4x3.h
@@ -10,6 +10,8 @@ static PyMethodDef himat4x3_methods[] = {
 	{ "__setstate__", (PyCFunction)mat_setstate<4, 3, glm::i32>, METH_O, "Restores a state that was previously acquired"},
 	{ "to_list", (PyCFunction)mat_to_list<4, 3, glm::i32>, METH_NOARGS, "Return the components of this matrix as a nested list"},
 	{ "to_tuple", (PyCFunction)mat_to_tuple<4, 3, glm::i32>, METH_NOARGS, "Return the components of this matrix as a nested tuple"},
+	{ "to_bytes", (PyCFunction)generic_to_bytes, METH_NOARGS, "Create a bytes string from this object"},
+	{ "from_bytes", (PyCFunction)mat_from_bytes<4, 3, glm::i32>, METH_O | METH_STATIC, "Create a matrix from a bytes string"},
 	{ NULL }
 };
 static PyBufferProcs himat4x3BufferMethods = {
diff --git a/PyGLM/types/mat/int/mat4x4.h b/PyGLM/types/mat/int/mat4x4.h
index 24b19b7..8cf4116 100644
--- a/PyGLM/types/mat/int/mat4x4.h
+++ b/PyGLM/types/mat/int/mat4x4.h
@@ -10,6 +10,8 @@ static PyMethodDef himat4x4_methods[] = {
 	{ "__setstate__", (PyCFunction)mat_setstate<4, 4, glm::i32>, METH_O, "Restores a state that was previously acquired"},
 	{ "to_list", (PyCFunction)mat_to_list<4, 4, glm::i32>, METH_NOARGS, "Return the components of this matrix as a nested list"},
 	{ "to_tuple", (PyCFunction)mat_to_tuple<4, 4, glm::i32>, METH_NOARGS, "Return the components of this matrix as a nested tuple"},
+	{ "to_bytes", (PyCFunction)generic_to_bytes, METH_NOARGS, "Create a bytes string from this object"},
+	{ "from_bytes", (PyCFunction)mat_from_bytes<4, 4, glm::i32>, METH_O | METH_STATIC, "Create a matrix from a bytes string"},
 	{ NULL }
 };
 static PyBufferProcs himat4x4BufferMethods = {
diff --git a/PyGLM/types/mat/uint/mat2x2.h b/PyGLM/types/mat/uint/mat2x2.h
index 123df0d..bed5a2e 100644
--- a/PyGLM/types/mat/uint/mat2x2.h
+++ b/PyGLM/types/mat/uint/mat2x2.h
@@ -10,6 +10,8 @@ static PyMethodDef humat2x2_methods[] = {
 	{ "__setstate__", (PyCFunction)mat_setstate<2, 2, glm::u32>, METH_O, "Restores a state that was previously acquired"},
 	{ "to_list", (PyCFunction)mat_to_list<2, 2, glm::u32>, METH_NOARGS, "Return the components of this matrix as a nested list"},
 	{ "to_tuple", (PyCFunction)mat_to_tuple<2, 2, glm::u32>, METH_NOARGS, "Return the components of this matrix as a nested tuple"},
+	{ "to_bytes", (PyCFunction)generic_to_bytes, METH_NOARGS, "Create a bytes string from this object"},
+	{ "from_bytes", (PyCFunction)mat_from_bytes<2, 2, glm::u32>, METH_O | METH_STATIC, "Create a matrix from a bytes string"},
 	{ NULL }
 };
 static PyBufferProcs humat2x2BufferMethods = {
diff --git a/PyGLM/types/mat/uint/mat2x3.h b/PyGLM/types/mat/uint/mat2x3.h
index 19364c0..c7197ff 100644
--- a/PyGLM/types/mat/uint/mat2x3.h
+++ b/PyGLM/types/mat/uint/mat2x3.h
@@ -10,6 +10,8 @@ static PyMethodDef humat2x3_methods[] = {
 	{ "__setstate__", (PyCFunction)mat_setstate<2, 3, glm::u32>, METH_O, "Restores a state that was previously acquired"},
 	{ "to_list", (PyCFunction)mat_to_list<2, 3, glm::u32>, METH_NOARGS, "Return the components of this matrix as a nested list"},
 	{ "to_tuple", (PyCFunction)mat_to_tuple<2, 3, glm::u32>, METH_NOARGS, "Return the components of this matrix as a nested tuple"},
+	{ "to_bytes", (PyCFunction)generic_to_bytes, METH_NOARGS, "Create a bytes string from this object"},
+	{ "from_bytes", (PyCFunction)mat_from_bytes<2, 3, glm::u32>, METH_O | METH_STATIC, "Create a matrix from a bytes string"},
 	{ NULL }
 };
 static PyBufferProcs humat2x3BufferMethods = {
diff --git a/PyGLM/types/mat/uint/mat2x4.h b/PyGLM/types/mat/uint/mat2x4.h
index c92b68b..3c0b017 100644
--- a/PyGLM/types/mat/uint/mat2x4.h
+++ b/PyGLM/types/mat/uint/mat2x4.h
@@ -10,6 +10,8 @@ static PyMethodDef humat2x4_methods[] = {
 	{ "__setstate__", (PyCFunction)mat_setstate<2, 4, glm::u32>, METH_O, "Restores a state that was previously acquired"},
 	{ "to_list", (PyCFunction)mat_to_list<2, 4, glm::u32>, METH_NOARGS, "Return the components of this matrix as a nested list"},
 	{ "to_tuple", (PyCFunction)mat_to_tuple<2, 4, glm::u32>, METH_NOARGS, "Return the components of this matrix as a nested tuple"},
+	{ "to_bytes", (PyCFunction)generic_to_bytes, METH_NOARGS, "Create a bytes string from this object"},
+	{ "from_bytes", (PyCFunction)mat_from_bytes<2, 4, glm::u32>, METH_O | METH_STATIC, "Create a matrix from a bytes string"},
 	{ NULL }
 };
 static PyBufferProcs humat2x4BufferMethods = {
diff --git a/PyGLM/types/mat/uint/mat3x2.h b/PyGLM/types/mat/uint/mat3x2.h
index 54ea2dc..1e7788d 100644
--- a/PyGLM/types/mat/uint/mat3x2.h
+++ b/PyGLM/types/mat/uint/mat3x2.h
@@ -10,6 +10,8 @@ static PyMethodDef humat3x2_methods[] = {
 	{ "__setstate__", (PyCFunction)mat_setstate<3, 2, glm::u32>, METH_O, "Restores a state that was previously acquired"},
 	{ "to_list", (PyCFunction)mat_to_list<3, 2, glm::u32>, METH_NOARGS, "Return the components of this matrix as a nested list"},
 	{ "to_tuple", (PyCFunction)mat_to_tuple<3, 2, glm::u32>, METH_NOARGS, "Return the components of this matrix as a nested tuple"},
+	{ "to_bytes", (PyCFunction)generic_to_bytes, METH_NOARGS, "Create a bytes string from this object"},
+	{ "from_bytes", (PyCFunction)mat_from_bytes<3, 2, glm::u32>, METH_O | METH_STATIC, "Create a matrix from a bytes string"},
 	{ NULL }
 };
 static PyBufferProcs humat3x2BufferMethods = {
diff --git a/PyGLM/types/mat/uint/mat3x3.h b/PyGLM/types/mat/uint/mat3x3.h
index fa555c4..02613c7 100644
--- a/PyGLM/types/mat/uint/mat3x3.h
+++ b/PyGLM/types/mat/uint/mat3x3.h
@@ -10,6 +10,8 @@ static PyMethodDef humat3x3_methods[] = {
 	{ "__setstate__", (PyCFunction)mat_setstate<3, 3, glm::u32>, METH_O, "Restores a state that was previously acquired"},
 	{ "to_list", (PyCFunction)mat_to_list<3, 3, glm::u32>, METH_NOARGS, "Return the components of this matrix as a nested list"},
 	{ "to_tuple", (PyCFunction)mat_to_tuple<3, 3, glm::u32>, METH_NOARGS, "Return the components of this matrix as a nested tuple"},
+	{ "to_bytes", (PyCFunction)generic_to_bytes, METH_NOARGS, "Create a bytes string from this object"},
+	{ "from_bytes", (PyCFunction)mat_from_bytes<3, 3, glm::u32>, METH_O | METH_STATIC, "Create a matrix from a bytes string"},
 	{ NULL }
 };
 static PyBufferProcs humat3x3BufferMethods = {
diff --git a/PyGLM/types/mat/uint/mat3x4.h b/PyGLM/types/mat/uint/mat3x4.h
index 972ab82..f9bd20c 100644
--- a/PyGLM/types/mat/uint/mat3x4.h
+++ b/PyGLM/types/mat/uint/mat3x4.h
@@ -10,6 +10,8 @@ static PyMethodDef humat3x4_methods[] = {
 	{ "__setstate__", (PyCFunction)mat_setstate<3, 4, glm::u32>, METH_O, "Restores a state that was previously acquired"},
 	{ "to_list", (PyCFunction)mat_to_list<3, 4, glm::u32>, METH_NOARGS, "Return the components of this matrix as a nested list"},
 	{ "to_tuple", (PyCFunction)mat_to_tuple<3, 4, glm::u32>, METH_NOARGS, "Return the components of this matrix as a nested tuple"},
+	{ "to_bytes", (PyCFunction)generic_to_bytes, METH_NOARGS, "Create a bytes string from this object"},
+	{ "from_bytes", (PyCFunction)mat_from_bytes<3, 4, glm::u32>, METH_O | METH_STATIC, "Create a matrix from a bytes string"},
 	{ NULL }
 };
 static PyBufferProcs humat3x4BufferMethods = {
diff --git a/PyGLM/types/mat/uint/mat4x2.h b/PyGLM/types/mat/uint/mat4x2.h
index f7fb941..d2cb0b3 100644
--- a/PyGLM/types/mat/uint/mat4x2.h
+++ b/PyGLM/types/mat/uint/mat4x2.h
@@ -10,6 +10,8 @@ static PyMethodDef humat4x2_methods[] = {
 	{ "__setstate__", (PyCFunction)mat_setstate<4, 2, glm::u32>, METH_O, "Restores a state that was previously acquired"},
 	{ "to_list", (PyCFunction)mat_to_list<4, 2, glm::u32>, METH_NOARGS, "Return the components of this matrix as a nested list"},
 	{ "to_tuple", (PyCFunction)mat_to_tuple<4, 2, glm::u32>, METH_NOARGS, "Return the components of this matrix as a nested tuple"},
+	{ "to_bytes", (PyCFunction)generic_to_bytes, METH_NOARGS, "Create a bytes string from this object"},
+	{ "from_bytes", (PyCFunction)mat_from_bytes<4, 2, glm::u32>, METH_O | METH_STATIC, "Create a matrix from a bytes string"},
 	{ NULL }
 };
 static PyBufferProcs humat4x2BufferMethods = {
diff --git a/PyGLM/types/mat/uint/mat4x3.h b/PyGLM/types/mat/uint/mat4x3.h
index ee9bcf7..8caacf8 100644
--- a/PyGLM/types/mat/uint/mat4x3.h
+++ b/PyGLM/types/mat/uint/mat4x3.h
@@ -10,6 +10,8 @@ static PyMethodDef humat4x3_methods[] = {
 	{ "__setstate__", (PyCFunction)mat_setstate<4, 3, glm::u32>, METH_O, "Restores a state that was previously acquired"},
 	{ "to_list", (PyCFunction)mat_to_list<4, 3, glm::u32>, METH_NOARGS, "Return the components of this matrix as a nested list"},
 	{ "to_tuple", (PyCFunction)mat_to_tuple<4, 3, glm::u32>, METH_NOARGS, "Return the components of this matrix as a nested tuple"},
+	{ "to_bytes", (PyCFunction)generic_to_bytes, METH_NOARGS, "Create a bytes string from this object"},
+	{ "from_bytes", (PyCFunction)mat_from_bytes<4, 3, glm::u32>, METH_O | METH_STATIC, "Create a matrix from a bytes string"},
 	{ NULL }
 };
 static PyBufferProcs humat4x3BufferMethods = {
diff --git a/PyGLM/types/mat/uint/mat4x4.h b/PyGLM/types/mat/uint/mat4x4.h
index eda975f..1b9f813 100644
--- a/PyGLM/types/mat/uint/mat4x4.h
+++ b/PyGLM/types/mat/uint/mat4x4.h
@@ -10,6 +10,8 @@ static PyMethodDef humat4x4_methods[] = {
 	{ "__setstate__", (PyCFunction)mat_setstate<4, 4, glm::u32>, METH_O, "Restores a state that was previously acquired"},
 	{ "to_list", (PyCFunction)mat_to_list<4, 4, glm::u32>, METH_NOARGS, "Return the components of this matrix as a nested list"},
 	{ "to_tuple", (PyCFunction)mat_to_tuple<4, 4, glm::u32>, METH_NOARGS, "Return the components of this matrix as a nested tuple"},
+	{ "to_bytes", (PyCFunction)generic_to_bytes, METH_NOARGS, "Create a bytes string from this object"},
+	{ "from_bytes", (PyCFunction)mat_from_bytes<4, 4, glm::u32>, METH_O | METH_STATIC, "Create a matrix from a bytes string"},
 	{ NULL }
 };
 static PyBufferProcs humat4x4BufferMethods = {
diff --git a/PyGLM/types/mvec/double/mvec2.h b/PyGLM/types/mvec/double/mvec2.h
index 7c0097a..5a5f2f0 100644
--- a/PyGLM/types/mvec/double/mvec2.h
+++ b/PyGLM/types/mvec/double/mvec2.h
@@ -11,6 +11,7 @@ static PyMethodDef hdmvec2_methods[] = {
 	{ "__setstate__", (PyCFunction)mvec2_setstate<double>, METH_O, "Restores a state that was previously acquired"},
 	{ "to_list", (PyCFunction)mvec2_to_list<double>, METH_NOARGS, "Return the components of this vector as a list"},
 	{ "to_tuple", (PyCFunction)mvec2_to_tuple<double>, METH_NOARGS, "Return the components of this vector as a tuple"},
+	{ "to_bytes", (PyCFunction)generic_to_bytes, METH_NOARGS, "Create a bytes string from this object"},
 	{ NULL }  /* Sentinel */
 };
 static PyBufferProcs hdmvec2BufferMethods = {
diff --git a/PyGLM/types/mvec/double/mvec3.h b/PyGLM/types/mvec/double/mvec3.h
index c4a955e..0bacba4 100644
--- a/PyGLM/types/mvec/double/mvec3.h
+++ b/PyGLM/types/mvec/double/mvec3.h
@@ -11,6 +11,7 @@ static PyMethodDef hdmvec3_methods[] = {
 	{ "__setstate__", (PyCFunction)mvec3_setstate<double>, METH_O, "Restores a state that was previously acquired"},
 	{ "to_list", (PyCFunction)mvec3_to_list<double>, METH_NOARGS, "Return the components of this vector as a list"},
 	{ "to_tuple", (PyCFunction)mvec3_to_tuple<double>, METH_NOARGS, "Return the components of this vector as a tuple"},
+	{ "to_bytes", (PyCFunction)generic_to_bytes, METH_NOARGS, "Create a bytes string from this object"},
 	{ NULL }  /* Sentinel */
 };
 static PyBufferProcs hdmvec3BufferMethods = {
diff --git a/PyGLM/types/mvec/double/mvec4.h b/PyGLM/types/mvec/double/mvec4.h
index eef6f74..89d0bdc 100644
--- a/PyGLM/types/mvec/double/mvec4.h
+++ b/PyGLM/types/mvec/double/mvec4.h
@@ -11,6 +11,7 @@ static PyMethodDef hdmvec4_methods[] = {
 	{ "__setstate__", (PyCFunction)mvec4_setstate<double>, METH_O, "Restores a state that was previously acquired"},
 	{ "to_list", (PyCFunction)mvec4_to_list<double>, METH_NOARGS, "Return the components of this vector as a list"},
 	{ "to_tuple", (PyCFunction)mvec4_to_tuple<double>, METH_NOARGS, "Return the components of this vector as a tuple"},
+	{ "to_bytes", (PyCFunction)generic_to_bytes, METH_NOARGS, "Create a bytes string from this object"},
 	{ NULL }  /* Sentinel */
 };
 static PyBufferProcs hdmvec4BufferMethods = {
diff --git a/PyGLM/types/mvec/float/mvec2.h b/PyGLM/types/mvec/float/mvec2.h
index 855d64d..9c97c71 100644
--- a/PyGLM/types/mvec/float/mvec2.h
+++ b/PyGLM/types/mvec/float/mvec2.h
@@ -11,6 +11,7 @@ static PyMethodDef hfmvec2_methods[] = {
 	{ "__setstate__", (PyCFunction)mvec2_setstate<float>, METH_O, "Restores a state that was previously acquired"},
 	{ "to_list", (PyCFunction)mvec2_to_list<float>, METH_NOARGS, "Return the components of this vector as a list"},
 	{ "to_tuple", (PyCFunction)mvec2_to_tuple<float>, METH_NOARGS, "Return the components of this vector as a tuple"},
+	{ "to_bytes", (PyCFunction)generic_to_bytes, METH_NOARGS, "Create a bytes string from this object"},
 	{ NULL }  /* Sentinel */
 };
 static PyBufferProcs hfmvec2BufferMethods = {
diff --git a/PyGLM/types/mvec/float/mvec3.h b/PyGLM/types/mvec/float/mvec3.h
index 73e4b02..5b179c7 100644
--- a/PyGLM/types/mvec/float/mvec3.h
+++ b/PyGLM/types/mvec/float/mvec3.h
@@ -11,6 +11,7 @@ static PyMethodDef hfmvec3_methods[] = {
 	{ "__setstate__", (PyCFunction)mvec3_setstate<float>, METH_O, "Restores a state that was previously acquired"},
 	{ "to_list", (PyCFunction)mvec3_to_list<float>, METH_NOARGS, "Return the components of this vector as a list"},
 	{ "to_tuple", (PyCFunction)mvec3_to_tuple<float>, METH_NOARGS, "Return the components of this vector as a tuple"},
+	{ "to_bytes", (PyCFunction)generic_to_bytes, METH_NOARGS, "Create a bytes string from this object"},
 	{ NULL }  /* Sentinel */
 };
 static PyBufferProcs hfmvec3BufferMethods = {
diff --git a/PyGLM/types/mvec/float/mvec4.h b/PyGLM/types/mvec/float/mvec4.h
index 8a2ac5e..59af69a 100644
--- a/PyGLM/types/mvec/float/mvec4.h
+++ b/PyGLM/types/mvec/float/mvec4.h
@@ -11,6 +11,7 @@ static PyMethodDef hfmvec4_methods[] = {
 	{ "__setstate__", (PyCFunction)mvec4_setstate<float>, METH_O, "Restores a state that was previously acquired"},
 	{ "to_list", (PyCFunction)mvec4_to_list<float>, METH_NOARGS, "Return the components of this vector as a list"},
 	{ "to_tuple", (PyCFunction)mvec4_to_tuple<float>, METH_NOARGS, "Return the components of this vector as a tuple"},
+	{ "to_bytes", (PyCFunction)generic_to_bytes, METH_NOARGS, "Create a bytes string from this object"},
 	{ NULL }  /* Sentinel */
 };
 static PyBufferProcs hfmvec4BufferMethods = {
diff --git a/PyGLM/types/mvec/int/mvec2.h b/PyGLM/types/mvec/int/mvec2.h
index 9794023..3db4feb 100644
--- a/PyGLM/types/mvec/int/mvec2.h
+++ b/PyGLM/types/mvec/int/mvec2.h
@@ -11,6 +11,7 @@ static PyMethodDef himvec2_methods[] = {
 	{ "__setstate__", (PyCFunction)mvec2_setstate<glm::i32>, METH_O, "Restores a state that was previously acquired"},
 	{ "to_list", (PyCFunction)mvec2_to_list<glm::i32>, METH_NOARGS, "Return the components of this vector as a list"},
 	{ "to_tuple", (PyCFunction)mvec2_to_tuple<glm::i32>, METH_NOARGS, "Return the components of this vector as a tuple"},
+	{ "to_bytes", (PyCFunction)generic_to_bytes, METH_NOARGS, "Create a bytes string from this object"},
 	{ NULL }  /* Sentinel */
 };
 static PyBufferProcs himvec2BufferMethods = {
diff --git a/PyGLM/types/mvec/int/mvec3.h b/PyGLM/types/mvec/int/mvec3.h
index aa3d1bb..ff6f64b 100644
--- a/PyGLM/types/mvec/int/mvec3.h
+++ b/PyGLM/types/mvec/int/mvec3.h
@@ -11,6 +11,7 @@ static PyMethodDef himvec3_methods[] = {
 	{ "__setstate__", (PyCFunction)mvec3_setstate<glm::i32>, METH_O, "Restores a state that was previously acquired"},
 	{ "to_list", (PyCFunction)mvec3_to_list<glm::i32>, METH_NOARGS, "Return the components of this vector as a list"},
 	{ "to_tuple", (PyCFunction)mvec3_to_tuple<glm::i32>, METH_NOARGS, "Return the components of this vector as a tuple"},
+	{ "to_bytes", (PyCFunction)generic_to_bytes, METH_NOARGS, "Create a bytes string from this object"},
 	{ NULL }  /* Sentinel */
 };
 static PyBufferProcs himvec3BufferMethods = {
diff --git a/PyGLM/types/mvec/int/mvec4.h b/PyGLM/types/mvec/int/mvec4.h
index d6df85d..3e2b138 100644
--- a/PyGLM/types/mvec/int/mvec4.h
+++ b/PyGLM/types/mvec/int/mvec4.h
@@ -11,6 +11,7 @@ static PyMethodDef himvec4_methods[] = {
 	{ "__setstate__", (PyCFunction)mvec4_setstate<glm::i32>, METH_O, "Restores a state that was previously acquired"},
 	{ "to_list", (PyCFunction)mvec4_to_list<glm::i32>, METH_NOARGS, "Return the components of this vector as a list"},
 	{ "to_tuple", (PyCFunction)mvec4_to_tuple<glm::i32>, METH_NOARGS, "Return the components of this vector as a tuple"},
+	{ "to_bytes", (PyCFunction)generic_to_bytes, METH_NOARGS, "Create a bytes string from this object"},
 	{ NULL }  /* Sentinel */
 };
 static PyBufferProcs himvec4BufferMethods = {
diff --git a/PyGLM/types/mvec/uint/mvec2.h b/PyGLM/types/mvec/uint/mvec2.h
index 23b3bf5..32cd3f6 100644
--- a/PyGLM/types/mvec/uint/mvec2.h
+++ b/PyGLM/types/mvec/uint/mvec2.h
@@ -11,6 +11,7 @@ static PyMethodDef humvec2_methods[] = {
 	{ "__setstate__", (PyCFunction)mvec2_setstate<glm::u32>, METH_O, "Restores a state that was previously acquired"},
 	{ "to_list", (PyCFunction)mvec2_to_list<glm::u32>, METH_NOARGS, "Return the components of this vector as a list"},
 	{ "to_tuple", (PyCFunction)mvec2_to_tuple<glm::u32>, METH_NOARGS, "Return the components of this vector as a tuple"},
+	{ "to_bytes", (PyCFunction)generic_to_bytes, METH_NOARGS, "Create a bytes string from this object"},
 	{ NULL }  /* Sentinel */
 };
 static PyBufferProcs humvec2BufferMethods = {
diff --git a/PyGLM/types/mvec/uint/mvec3.h b/PyGLM/types/mvec/uint/mvec3.h
index fb74a26..93b0082 100644
--- a/PyGLM/types/mvec/uint/mvec3.h
+++ b/PyGLM/types/mvec/uint/mvec3.h
@@ -11,6 +11,7 @@ static PyMethodDef humvec3_methods[] = {
 	{ "__setstate__", (PyCFunction)mvec3_setstate<glm::u32>, METH_O, "Restores a state that was previously acquired"},
 	{ "to_list", (PyCFunction)mvec3_to_list<glm::u32>, METH_NOARGS, "Return the components of this vector as a list"},
 	{ "to_tuple", (PyCFunction)mvec3_to_tuple<glm::u32>, METH_NOARGS, "Return the components of this vector as a tuple"},
+	{ "to_bytes", (PyCFunction)generic_to_bytes, METH_NOARGS, "Create a bytes string from this object"},
 	{ NULL }  /* Sentinel */
 };
 static PyBufferProcs humvec3BufferMethods = {
diff --git a/PyGLM/types/mvec/uint/mvec4.h b/PyGLM/types/mvec/uint/mvec4.h
index 46f1f40..e1b8215 100644
--- a/PyGLM/types/mvec/uint/mvec4.h
+++ b/PyGLM/types/mvec/uint/mvec4.h
@@ -11,6 +11,7 @@ static PyMethodDef humvec4_methods[] = {
 	{ "__setstate__", (PyCFunction)mvec4_setstate<glm::u32>, METH_O, "Restores a state that was previously acquired"},
 	{ "to_list", (PyCFunction)mvec4_to_list<glm::u32>, METH_NOARGS, "Return the components of this vector as a list"},
 	{ "to_tuple", (PyCFunction)mvec4_to_tuple<glm::u32>, METH_NOARGS, "Return the components of this vector as a tuple"},
+	{ "to_bytes", (PyCFunction)generic_to_bytes, METH_NOARGS, "Create a bytes string from this object"},
 	{ NULL }  /* Sentinel */
 };
 static PyBufferProcs humvec4BufferMethods = {
diff --git a/PyGLM/types/qua/double/quat.h b/PyGLM/types/qua/double/quat.h
index eaa3f59..42e278d 100644
--- a/PyGLM/types/qua/double/quat.h
+++ b/PyGLM/types/qua/double/quat.h
@@ -10,6 +10,8 @@ static PyMethodDef hdqua_methods[] = {
 	{ "__setstate__", (PyCFunction)qua_setstate<double>, METH_O, "Restores a state that was previously acquired"},
 	{ "to_list", (PyCFunction)qua_to_list<double>, METH_NOARGS, "Return the components of this quaterion as a list"},
 	{ "to_tuple", (PyCFunction)qua_to_tuple<double>, METH_NOARGS, "Return the components of this quaterion as a tuple"},
+	{ "to_bytes", (PyCFunction)generic_to_bytes, METH_NOARGS, "Create a bytes string from this object"},
+	{ "from_bytes", (PyCFunction)qua_from_bytes<double>, METH_O | METH_STATIC, "Create a quaternion from a bytes string"},
 	{ NULL }
 };
 
diff --git a/PyGLM/types/qua/float/quat.h b/PyGLM/types/qua/float/quat.h
index cfaed4e..aae2e82 100644
--- a/PyGLM/types/qua/float/quat.h
+++ b/PyGLM/types/qua/float/quat.h
@@ -10,6 +10,8 @@ static PyMethodDef hfqua_methods[] = {
 	{ "__setstate__", (PyCFunction)qua_setstate<float>, METH_O, "Restores a state that was previously acquired"},
 	{ "to_list", (PyCFunction)qua_to_list<float>, METH_NOARGS, "Return the components of this quaterion as a list"},
 	{ "to_tuple", (PyCFunction)qua_to_tuple<float>, METH_NOARGS, "Return the components of this quaterion as a tuple"},
+	{ "to_bytes", (PyCFunction)generic_to_bytes, METH_NOARGS, "Create a bytes string from this object"},
+	{ "from_bytes", (PyCFunction)qua_from_bytes<float>, METH_O | METH_STATIC, "Create a quaternion from a bytes string"},
 	{ NULL }
 };
 
diff --git a/PyGLM/types/qua/forward_declarations.h b/PyGLM/types/qua/forward_declarations.h
index 3004110..7b128e6 100644
--- a/PyGLM/types/qua/forward_declarations.h
+++ b/PyGLM/types/qua/forward_declarations.h
@@ -84,6 +84,9 @@ static PyObject* quaIter_next(quaIter<T> *rgstate);
 template<typename T>
 static PyObject* quaIter_new(PyTypeObject *type, PyObject *args, PyObject *kwargs);
 
+template<typename T>
+static PyObject* qua_from_bytes(PyObject*, PyObject* arg);
+
 template<typename T>
 static Py_hash_t qua_hash(qua<T>* self, PyObject*);
 
diff --git a/PyGLM/types/vec/bool/vec1.h b/PyGLM/types/vec/bool/vec1.h
index 487381f..d083733 100644
--- a/PyGLM/types/vec/bool/vec1.h
+++ b/PyGLM/types/vec/bool/vec1.h
@@ -15,6 +15,8 @@ static PyMethodDef hbvec1_methods[] = {
 	{ "__setstate__", (PyCFunction)vec1_setstate<bool>, METH_O, "Restores a state that was previously acquired"},
 	{ "to_list", (PyCFunction)vec1_to_list<bool>, METH_NOARGS, "Return the components of this vector as a list"},
 	{ "to_tuple", (PyCFunction)vec1_to_tuple<bool>, METH_NOARGS, "Return the components of this vector as a tuple"},
+	{ "to_bytes", (PyCFunction)generic_to_bytes, METH_NOARGS, "Create a bytes string from this object"},
+	{ "from_bytes", (PyCFunction)vec_from_bytes<1, bool>, METH_O | METH_STATIC, "Create a vector from a bytes string"},
 	{ NULL }  /* Sentinel */
 };
 static PyBufferProcs hbvec1BufferMethods = {
diff --git a/PyGLM/types/vec/bool/vec2.h b/PyGLM/types/vec/bool/vec2.h
index 06378a3..b9c3988 100644
--- a/PyGLM/types/vec/bool/vec2.h
+++ b/PyGLM/types/vec/bool/vec2.h
@@ -16,6 +16,8 @@ static PyMethodDef hbvec2_methods[] = {
 	{ "__setstate__", (PyCFunction)vec2_setstate<bool>, METH_O, "Restores a state that was previously acquired"},
 	{ "to_list", (PyCFunction)vec2_to_list<bool>, METH_NOARGS, "Return the components of this vector as a list"},
 	{ "to_tuple", (PyCFunction)vec2_to_tuple<bool>, METH_NOARGS, "Return the components of this vector as a tuple"},
+	{ "to_bytes", (PyCFunction)generic_to_bytes, METH_NOARGS, "Create a bytes string from this object"},
+	{ "from_bytes", (PyCFunction)vec_from_bytes<2, bool>, METH_O | METH_STATIC, "Create a vector from a bytes string"},
 	{ NULL }  /* Sentinel */
 };
 static PyBufferProcs hbvec2BufferMethods = {
diff --git a/PyGLM/types/vec/bool/vec3.h b/PyGLM/types/vec/bool/vec3.h
index aa34e46..f5fd539 100644
--- a/PyGLM/types/vec/bool/vec3.h
+++ b/PyGLM/types/vec/bool/vec3.h
@@ -17,6 +17,8 @@ static PyMethodDef hbvec3_methods[] = {
 	{ "__setstate__", (PyCFunction)vec3_setstate<bool>, METH_O, "Restores a state that was previously acquired"},
 	{ "to_list", (PyCFunction)vec3_to_list<bool>, METH_NOARGS, "Return the components of this vector as a list"},
 	{ "to_tuple", (PyCFunction)vec3_to_tuple<bool>, METH_NOARGS, "Return the components of this vector as a tuple"},
+	{ "to_bytes", (PyCFunction)generic_to_bytes, METH_NOARGS, "Create a bytes string from this object"},
+	{ "from_bytes", (PyCFunction)vec_from_bytes<3, bool>, METH_O | METH_STATIC, "Create a vector from a bytes string"},
 	{ NULL }  /* Sentinel */
 };
 static PyBufferProcs hbvec3BufferMethods = {
diff --git a/PyGLM/types/vec/bool/vec4.h b/PyGLM/types/vec/bool/vec4.h
index 6214d1f..8ecf443 100644
--- a/PyGLM/types/vec/bool/vec4.h
+++ b/PyGLM/types/vec/bool/vec4.h
@@ -18,6 +18,8 @@ static PyMethodDef hbvec4_methods[] = {
 	{ "__setstate__", (PyCFunction)vec4_setstate<bool>, METH_O, "Restores a state that was previously acquired"},
 	{ "to_list", (PyCFunction)vec4_to_list<bool>, METH_NOARGS, "Return the components of this vector as a list"},
 	{ "to_tuple", (PyCFunction)vec4_to_tuple<bool>, METH_NOARGS, "Return the components of this vector as a tuple"},
+	{ "to_bytes", (PyCFunction)generic_to_bytes, METH_NOARGS, "Create a bytes string from this object"},
+	{ "from_bytes", (PyCFunction)vec_from_bytes<4, bool>, METH_O | METH_STATIC, "Create a vector from a bytes string"},
 	{ NULL }  /* Sentinel */
 };
 static PyBufferProcs hbvec4BufferMethods = {
diff --git a/PyGLM/types/vec/double/vec1.h b/PyGLM/types/vec/double/vec1.h
index 53267d5..1b57e48 100644
--- a/PyGLM/types/vec/double/vec1.h
+++ b/PyGLM/types/vec/double/vec1.h
@@ -15,6 +15,8 @@ static PyMethodDef hdvec1_methods[] = {
 	{ "__setstate__", (PyCFunction)vec1_setstate<double>, METH_O, "Restores a state that was previously acquired"},
 	{ "to_list", (PyCFunction)vec1_to_list<double>, METH_NOARGS, "Return the components of this vector as a list"},
 	{ "to_tuple", (PyCFunction)vec1_to_tuple<double>, METH_NOARGS, "Return the components of this vector as a tuple"},
+	{ "to_bytes", (PyCFunction)generic_to_bytes, METH_NOARGS, "Create a bytes string from this object"},
+	{ "from_bytes", (PyCFunction)vec_from_bytes<1, double>, METH_O | METH_STATIC, "Create a vector from a bytes string"},
 	{ NULL }  /* Sentinel */
 };
 static PyBufferProcs hdvec1BufferMethods = {
diff --git a/PyGLM/types/vec/double/vec2.h b/PyGLM/types/vec/double/vec2.h
index 805ddee..a460a8f 100644
--- a/PyGLM/types/vec/double/vec2.h
+++ b/PyGLM/types/vec/double/vec2.h
@@ -16,6 +16,8 @@ static PyMethodDef hdvec2_methods[] = {
 	{ "__setstate__", (PyCFunction)vec2_setstate<double>, METH_O, "Restores a state that was previously acquired"},
 	{ "to_list", (PyCFunction)vec2_to_list<double>, METH_NOARGS, "Return the components of this vector as a list"},
 	{ "to_tuple", (PyCFunction)vec2_to_tuple<double>, METH_NOARGS, "Return the components of this vector as a tuple"},
+	{ "to_bytes", (PyCFunction)generic_to_bytes, METH_NOARGS, "Create a bytes string from this object"},
+	{ "from_bytes", (PyCFunction)vec_from_bytes<2, double>, METH_O | METH_STATIC, "Create a vector from a bytes string"},
 	{ NULL }  /* Sentinel */
 };
 static PyBufferProcs hdvec2BufferMethods = {
diff --git a/PyGLM/types/vec/double/vec3.h b/PyGLM/types/vec/double/vec3.h
index d5ed4ba..815903c 100644
--- a/PyGLM/types/vec/double/vec3.h
+++ b/PyGLM/types/vec/double/vec3.h
@@ -17,6 +17,8 @@ static PyMethodDef hdvec3_methods[] = {
 	{ "__setstate__", (PyCFunction)vec3_setstate<double>, METH_O, "Restores a state that was previously acquired"},
 	{ "to_list", (PyCFunction)vec3_to_list<double>, METH_NOARGS, "Return the components of this vector as a list"},
 	{ "to_tuple", (PyCFunction)vec3_to_tuple<double>, METH_NOARGS, "Return the components of this vector as a tuple"},
+	{ "to_bytes", (PyCFunction)generic_to_bytes, METH_NOARGS, "Create a bytes string from this object"},
+	{ "from_bytes", (PyCFunction)vec_from_bytes<3, double>, METH_O | METH_STATIC, "Create a vector from a bytes string"},
 	{ NULL }  /* Sentinel */
 };
 static PyBufferProcs hdvec3BufferMethods = {
diff --git a/PyGLM/types/vec/double/vec4.h b/PyGLM/types/vec/double/vec4.h
index ad617a3..72166b5 100644
--- a/PyGLM/types/vec/double/vec4.h
+++ b/PyGLM/types/vec/double/vec4.h
@@ -18,6 +18,8 @@ static PyMethodDef hdvec4_methods[] = {
 	{ "__setstate__", (PyCFunction)vec4_setstate<double>, METH_O, "Restores a state that was previously acquired"},
 	{ "to_list", (PyCFunction)vec4_to_list<double>, METH_NOARGS, "Return the components of this vector as a list"},
 	{ "to_tuple", (PyCFunction)vec4_to_tuple<double>, METH_NOARGS, "Return the components of this vector as a tuple"},
+	{ "to_bytes", (PyCFunction)generic_to_bytes, METH_NOARGS, "Create a bytes string from this object"},
+	{ "from_bytes", (PyCFunction)vec_from_bytes<4, double>, METH_O | METH_STATIC, "Create a vector from a bytes string"},
 	{ NULL }  /* Sentinel */
 };
 static PyBufferProcs hdvec4BufferMethods = {
diff --git a/PyGLM/types/vec/float/vec1.h b/PyGLM/types/vec/float/vec1.h
index 5a990ea..65bbdac 100644
--- a/PyGLM/types/vec/float/vec1.h
+++ b/PyGLM/types/vec/float/vec1.h
@@ -15,6 +15,8 @@ static PyMethodDef hfvec1_methods[] = {
 	{ "__setstate__", (PyCFunction)vec1_setstate<float>, METH_O, "Restores a state that was previously acquired"},
 	{ "to_list", (PyCFunction)vec1_to_list<float>, METH_NOARGS, "Return the components of this vector as a list"},
 	{ "to_tuple", (PyCFunction)vec1_to_tuple<float>, METH_NOARGS, "Return the components of this vector as a tuple"},
+	{ "to_bytes", (PyCFunction)generic_to_bytes, METH_NOARGS, "Create a bytes string from this object"},
+	{ "from_bytes", (PyCFunction)vec_from_bytes<1, float>, METH_O | METH_STATIC, "Create a vector from a bytes string"},
 	{ NULL }  /* Sentinel */
 };
 static PyBufferProcs hfvec1BufferMethods = {
diff --git a/PyGLM/types/vec/float/vec2.h b/PyGLM/types/vec/float/vec2.h
index af65c9a..ed1d8b5 100644
--- a/PyGLM/types/vec/float/vec2.h
+++ b/PyGLM/types/vec/float/vec2.h
@@ -16,6 +16,8 @@ static PyMethodDef hfvec2_methods[] = {
 	{ "__setstate__", (PyCFunction)vec2_setstate<float>, METH_O, "Restores a state that was previously acquired"},
 	{ "to_list", (PyCFunction)vec2_to_list<float>, METH_NOARGS, "Return the components of this vector as a list"},
 	{ "to_tuple", (PyCFunction)vec2_to_tuple<float>, METH_NOARGS, "Return the components of this vector as a tuple"},
+	{ "to_bytes", (PyCFunction)generic_to_bytes, METH_NOARGS, "Create a bytes string from this object"},
+	{ "from_bytes", (PyCFunction)vec_from_bytes<2, float>, METH_O | METH_STATIC, "Create a vector from a bytes string"},
 	{ NULL }  /* Sentinel */
 };
 static PyBufferProcs hfvec2BufferMethods = {
diff --git a/PyGLM/types/vec/float/vec3.h b/PyGLM/types/vec/float/vec3.h
index 22c2c2c..3e14ccf 100644
--- a/PyGLM/types/vec/float/vec3.h
+++ b/PyGLM/types/vec/float/vec3.h
@@ -17,6 +17,8 @@ static PyMethodDef hfvec3_methods[] = {
 	{ "__setstate__", (PyCFunction)vec3_setstate<float>, METH_O, "Restores a state that was previously acquired"},
 	{ "to_list", (PyCFunction)vec3_to_list<float>, METH_NOARGS, "Return the components of this vector as a list"},
 	{ "to_tuple", (PyCFunction)vec3_to_tuple<float>, METH_NOARGS, "Return the components of this vector as a tuple"},
+	{ "to_bytes", (PyCFunction)generic_to_bytes, METH_NOARGS, "Create a bytes string from this object"},
+	{ "from_bytes", (PyCFunction)vec_from_bytes<3, float>, METH_O | METH_STATIC, "Create a vector from a bytes string"},
 	{ NULL }  /* Sentinel */
 };
 static PyBufferProcs hfvec3BufferMethods = {
diff --git a/PyGLM/types/vec/float/vec4.h b/PyGLM/types/vec/float/vec4.h
index 9c6f134..01d7bc3 100644
--- a/PyGLM/types/vec/float/vec4.h
+++ b/PyGLM/types/vec/float/vec4.h
@@ -18,6 +18,8 @@ static PyMethodDef hfvec4_methods[] = {
 	{ "__setstate__", (PyCFunction)vec4_setstate<float>, METH_O, "Restores a state that was previously acquired"},
 	{ "to_list", (PyCFunction)vec4_to_list<float>, METH_NOARGS, "Return the components of this vector as a list"},
 	{ "to_tuple", (PyCFunction)vec4_to_tuple<float>, METH_NOARGS, "Return the components of this vector as a tuple"},
+	{ "to_bytes", (PyCFunction)generic_to_bytes, METH_NOARGS, "Create a bytes string from this object"},
+	{ "from_bytes", (PyCFunction)vec_from_bytes<4, float>, METH_O | METH_STATIC, "Create a vector from a bytes string"},
 	{ NULL }  /* Sentinel */
 };
 static PyBufferProcs hfvec4BufferMethods = {
diff --git a/PyGLM/types/vec/forward_declarations.h b/PyGLM/types/vec/forward_declarations.h
index 49f6a8f..f9fb60e 100644
--- a/PyGLM/types/vec/forward_declarations.h
+++ b/PyGLM/types/vec/forward_declarations.h
@@ -190,5 +190,8 @@ static PyObject* vec4Iter_next(vecIter<4, T> *rgstate);
 template<int L, typename T>
 static PyObject* vecIter_new(PyTypeObject *type, PyObject *args, PyObject *kwargs);
 
+template<int L, typename T>
+static PyObject* vec_from_bytes(PyObject*, PyObject* arg);
+
 template<int L, typename T>
 static Py_hash_t vec_hash(vec<L, T>* self, PyObject*);
\ No newline at end of file
diff --git a/PyGLM/types/vec/int16/vec1.h b/PyGLM/types/vec/int16/vec1.h
index 8d4cc24..b480f0a 100644
--- a/PyGLM/types/vec/int16/vec1.h
+++ b/PyGLM/types/vec/int16/vec1.h
@@ -15,6 +15,8 @@ static PyMethodDef hi16vec1_methods[] = {
 	{ "__setstate__", (PyCFunction)vec1_setstate<glm::i16>, METH_O, "Restores a state that was previously acquired"},
 	{ "to_list", (PyCFunction)vec1_to_list<glm::i16>, METH_NOARGS, "Return the components of this vector as a list"},
 	{ "to_tuple", (PyCFunction)vec1_to_tuple<glm::i16>, METH_NOARGS, "Return the components of this vector as a tuple"},
+	{ "to_bytes", (PyCFunction)generic_to_bytes, METH_NOARGS, "Create a bytes string from this object"},
+	{ "from_bytes", (PyCFunction)vec_from_bytes<1, glm::i16>, METH_O | METH_STATIC, "Create a vector from a bytes string"},
 	{ NULL }  /* Sentinel */
 };
 static PyBufferProcs hi16vec1BufferMethods = {
diff --git a/PyGLM/types/vec/int16/vec2.h b/PyGLM/types/vec/int16/vec2.h
index c029cd4..4d06157 100644
--- a/PyGLM/types/vec/int16/vec2.h
+++ b/PyGLM/types/vec/int16/vec2.h
@@ -16,6 +16,8 @@ static PyMethodDef hi16vec2_methods[] = {
 	{ "__setstate__", (PyCFunction)vec2_setstate<glm::i16>, METH_O, "Restores a state that was previously acquired"},
 	{ "to_list", (PyCFunction)vec2_to_list<glm::i16>, METH_NOARGS, "Return the components of this vector as a list"},
 	{ "to_tuple", (PyCFunction)vec2_to_tuple<glm::i16>, METH_NOARGS, "Return the components of this vector as a tuple"},
+	{ "to_bytes", (PyCFunction)generic_to_bytes, METH_NOARGS, "Create a bytes string from this object"},
+	{ "from_bytes", (PyCFunction)vec_from_bytes<2, glm::i16>, METH_O | METH_STATIC, "Create a vector from a bytes string"},
 	{ NULL }  /* Sentinel */
 };
 static PyBufferProcs hi16vec2BufferMethods = {
diff --git a/PyGLM/types/vec/int16/vec3.h b/PyGLM/types/vec/int16/vec3.h
index 1ad3b69..7513fbf 100644
--- a/PyGLM/types/vec/int16/vec3.h
+++ b/PyGLM/types/vec/int16/vec3.h
@@ -17,6 +17,8 @@ static PyMethodDef hi16vec3_methods[] = {
 	{ "__setstate__", (PyCFunction)vec3_setstate<glm::i16>, METH_O, "Restores a state that was previously acquired"},
 	{ "to_list", (PyCFunction)vec3_to_list<glm::i16>, METH_NOARGS, "Return the components of this vector as a list"},
 	{ "to_tuple", (PyCFunction)vec3_to_tuple<glm::i16>, METH_NOARGS, "Return the components of this vector as a tuple"},
+	{ "to_bytes", (PyCFunction)generic_to_bytes, METH_NOARGS, "Create a bytes string from this object"},
+	{ "from_bytes", (PyCFunction)vec_from_bytes<3, glm::i16>, METH_O | METH_STATIC, "Create a vector from a bytes string"},
 	{ NULL }  /* Sentinel */
 };
 static PyBufferProcs hi16vec3BufferMethods = {
diff --git a/PyGLM/types/vec/int16/vec4.h b/PyGLM/types/vec/int16/vec4.h
index 5ebf8c1..79d2e62 100644
--- a/PyGLM/types/vec/int16/vec4.h
+++ b/PyGLM/types/vec/int16/vec4.h
@@ -18,6 +18,8 @@ static PyMethodDef hi16vec4_methods[] = {
 	{ "__setstate__", (PyCFunction)vec4_setstate<glm::i16>, METH_O, "Restores a state that was previously acquired"},
 	{ "to_list", (PyCFunction)vec4_to_list<glm::i16>, METH_NOARGS, "Return the components of this vector as a list"},
 	{ "to_tuple", (PyCFunction)vec4_to_tuple<glm::i16>, METH_NOARGS, "Return the components of this vector as a tuple"},
+	{ "to_bytes", (PyCFunction)generic_to_bytes, METH_NOARGS, "Create a bytes string from this object"},
+	{ "from_bytes", (PyCFunction)vec_from_bytes<4, glm::i16>, METH_O | METH_STATIC, "Create a vector from a bytes string"},
 	{ NULL }  /* Sentinel */
 };
 static PyBufferProcs hi16vec4BufferMethods = {
diff --git a/PyGLM/types/vec/int32/vec1.h b/PyGLM/types/vec/int32/vec1.h
index eecda6d..67e0759 100644
--- a/PyGLM/types/vec/int32/vec1.h
+++ b/PyGLM/types/vec/int32/vec1.h
@@ -15,6 +15,8 @@ static PyMethodDef hivec1_methods[] = {
 	{ "__setstate__", (PyCFunction)vec1_setstate<glm::i32>, METH_O, "Restores a state that was previously acquired"},
 	{ "to_list", (PyCFunction)vec1_to_list<glm::i32>, METH_NOARGS, "Return the components of this vector as a list"},
 	{ "to_tuple", (PyCFunction)vec1_to_tuple<glm::i32>, METH_NOARGS, "Return the components of this vector as a tuple"},
+	{ "to_bytes", (PyCFunction)generic_to_bytes, METH_NOARGS, "Create a bytes string from this object"},
+	{ "from_bytes", (PyCFunction)vec_from_bytes<1, glm::i32>, METH_O | METH_STATIC, "Create a vector from a bytes string"},
 	{ NULL }  /* Sentinel */
 };
 static PyBufferProcs hivec1BufferMethods = {
diff --git a/PyGLM/types/vec/int32/vec2.h b/PyGLM/types/vec/int32/vec2.h
index 629890e..01fcbbd 100644
--- a/PyGLM/types/vec/int32/vec2.h
+++ b/PyGLM/types/vec/int32/vec2.h
@@ -16,6 +16,8 @@ static PyMethodDef hivec2_methods[] = {
 	{ "__setstate__", (PyCFunction)vec2_setstate<glm::i32>, METH_O, "Restores a state that was previously acquired"},
 	{ "to_list", (PyCFunction)vec2_to_list<glm::i32>, METH_NOARGS, "Return the components of this vector as a list"},
 	{ "to_tuple", (PyCFunction)vec2_to_tuple<glm::i32>, METH_NOARGS, "Return the components of this vector as a tuple"},
+	{ "to_bytes", (PyCFunction)generic_to_bytes, METH_NOARGS, "Create a bytes string from this object"},
+	{ "from_bytes", (PyCFunction)vec_from_bytes<2, glm::i32>, METH_O | METH_STATIC, "Create a vector from a bytes string"},
 	{ NULL }  /* Sentinel */
 };
 static PyBufferProcs hivec2BufferMethods = {
diff --git a/PyGLM/types/vec/int32/vec3.h b/PyGLM/types/vec/int32/vec3.h
index 5699e75..313f6bd 100644
--- a/PyGLM/types/vec/int32/vec3.h
+++ b/PyGLM/types/vec/int32/vec3.h
@@ -17,6 +17,8 @@ static PyMethodDef hivec3_methods[] = {
 	{ "__setstate__", (PyCFunction)vec3_setstate<glm::i32>, METH_O, "Restores a state that was previously acquired"},
 	{ "to_list", (PyCFunction)vec3_to_list<glm::i32>, METH_NOARGS, "Return the components of this vector as a list"},
 	{ "to_tuple", (PyCFunction)vec3_to_tuple<glm::i32>, METH_NOARGS, "Return the components of this vector as a tuple"},
+	{ "to_bytes", (PyCFunction)generic_to_bytes, METH_NOARGS, "Create a bytes string from this object"},
+	{ "from_bytes", (PyCFunction)vec_from_bytes<3, glm::i32>, METH_O | METH_STATIC, "Create a vector from a bytes string"},
 	{ NULL }  /* Sentinel */
 };
 static PyBufferProcs hivec3BufferMethods = {
diff --git a/PyGLM/types/vec/int32/vec4.h b/PyGLM/types/vec/int32/vec4.h
index b24ff5e..0738b43 100644
--- a/PyGLM/types/vec/int32/vec4.h
+++ b/PyGLM/types/vec/int32/vec4.h
@@ -18,6 +18,8 @@ static PyMethodDef hivec4_methods[] = {
 	{ "__setstate__", (PyCFunction)vec4_setstate<glm::i32>, METH_O, "Restores a state that was previously acquired"},
 	{ "to_list", (PyCFunction)vec4_to_list<glm::i32>, METH_NOARGS, "Return the components of this vector as a list"},
 	{ "to_tuple", (PyCFunction)vec4_to_tuple<glm::i32>, METH_NOARGS, "Return the components of this vector as a tuple"},
+	{ "to_bytes", (PyCFunction)generic_to_bytes, METH_NOARGS, "Create a bytes string from this object"},
+	{ "from_bytes", (PyCFunction)vec_from_bytes<4, glm::i32>, METH_O | METH_STATIC, "Create a vector from a bytes string"},
 	{ NULL }  /* Sentinel */
 };
 static PyBufferProcs hivec4BufferMethods = {
diff --git a/PyGLM/types/vec/int64/vec1.h b/PyGLM/types/vec/int64/vec1.h
index 31ba905..6a8b62d 100644
--- a/PyGLM/types/vec/int64/vec1.h
+++ b/PyGLM/types/vec/int64/vec1.h
@@ -15,6 +15,8 @@ static PyMethodDef hi64vec1_methods[] = {
 	{ "__setstate__", (PyCFunction)vec1_setstate<glm::i64>, METH_O, "Restores a state that was previously acquired"},
 	{ "to_list", (PyCFunction)vec1_to_list<glm::i64>, METH_NOARGS, "Return the components of this vector as a list"},
 	{ "to_tuple", (PyCFunction)vec1_to_tuple<glm::i64>, METH_NOARGS, "Return the components of this vector as a tuple"},
+	{ "to_bytes", (PyCFunction)generic_to_bytes, METH_NOARGS, "Create a bytes string from this object"},
+	{ "from_bytes", (PyCFunction)vec_from_bytes<1, glm::i64>, METH_O | METH_STATIC, "Create a vector from a bytes string"},
 	{ NULL }  /* Sentinel */
 };
 static PyBufferProcs hi64vec1BufferMethods = {
diff --git a/PyGLM/types/vec/int64/vec2.h b/PyGLM/types/vec/int64/vec2.h
index f159278..38f40fc 100644
--- a/PyGLM/types/vec/int64/vec2.h
+++ b/PyGLM/types/vec/int64/vec2.h
@@ -16,6 +16,8 @@ static PyMethodDef hi64vec2_methods[] = {
 	{ "__setstate__", (PyCFunction)vec2_setstate<glm::i64>, METH_O, "Restores a state that was previously acquired"},
 	{ "to_list", (PyCFunction)vec2_to_list<glm::i64>, METH_NOARGS, "Return the components of this vector as a list"},
 	{ "to_tuple", (PyCFunction)vec2_to_tuple<glm::i64>, METH_NOARGS, "Return the components of this vector as a tuple"},
+	{ "to_bytes", (PyCFunction)generic_to_bytes, METH_NOARGS, "Create a bytes string from this object"},
+	{ "from_bytes", (PyCFunction)vec_from_bytes<2, glm::i64>, METH_O | METH_STATIC, "Create a vector from a bytes string"},
 	{ NULL }  /* Sentinel */
 };
 static PyBufferProcs hi64vec2BufferMethods = {
diff --git a/PyGLM/types/vec/int64/vec3.h b/PyGLM/types/vec/int64/vec3.h
index 133d34e..69d7d8b 100644
--- a/PyGLM/types/vec/int64/vec3.h
+++ b/PyGLM/types/vec/int64/vec3.h
@@ -17,6 +17,8 @@ static PyMethodDef hi64vec3_methods[] = {
 	{ "__setstate__", (PyCFunction)vec3_setstate<glm::i64>, METH_O, "Restores a state that was previously acquired"},
 	{ "to_list", (PyCFunction)vec3_to_list<glm::i64>, METH_NOARGS, "Return the components of this vector as a list"},
 	{ "to_tuple", (PyCFunction)vec3_to_tuple<glm::i64>, METH_NOARGS, "Return the components of this vector as a tuple"},
+	{ "to_bytes", (PyCFunction)generic_to_bytes, METH_NOARGS, "Create a bytes string from this object"},
+	{ "from_bytes", (PyCFunction)vec_from_bytes<3, glm::i64>, METH_O | METH_STATIC, "Create a vector from a bytes string"},
 	{ NULL }  /* Sentinel */
 };
 static PyBufferProcs hi64vec3BufferMethods = {
diff --git a/PyGLM/types/vec/int64/vec4.h b/PyGLM/types/vec/int64/vec4.h
index bce5cd0..93e8cd1 100644
--- a/PyGLM/types/vec/int64/vec4.h
+++ b/PyGLM/types/vec/int64/vec4.h
@@ -18,6 +18,8 @@ static PyMethodDef hi64vec4_methods[] = {
 	{ "__setstate__", (PyCFunction)vec4_setstate<glm::i64>, METH_O, "Restores a state that was previously acquired"},
 	{ "to_list", (PyCFunction)vec4_to_list<glm::i64>, METH_NOARGS, "Return the components of this vector as a list"},
 	{ "to_tuple", (PyCFunction)vec4_to_tuple<glm::i64>, METH_NOARGS, "Return the components of this vector as a tuple"},
+	{ "to_bytes", (PyCFunction)generic_to_bytes, METH_NOARGS, "Create a bytes string from this object"},
+	{ "from_bytes", (PyCFunction)vec_from_bytes<4, glm::i64>, METH_O | METH_STATIC, "Create a vector from a bytes string"},
 	{ NULL }  /* Sentinel */
 };
 static PyBufferProcs hi64vec4BufferMethods = {
diff --git a/PyGLM/types/vec/int8/vec1.h b/PyGLM/types/vec/int8/vec1.h
index 69414f2..60f26bb 100644
--- a/PyGLM/types/vec/int8/vec1.h
+++ b/PyGLM/types/vec/int8/vec1.h
@@ -15,6 +15,8 @@ static PyMethodDef hi8vec1_methods[] = {
 	{ "__setstate__", (PyCFunction)vec1_setstate<glm::i8>, METH_O, "Restores a state that was previously acquired"},
 	{ "to_list", (PyCFunction)vec1_to_list<glm::i8>, METH_NOARGS, "Return the components of this vector as a list"},
 	{ "to_tuple", (PyCFunction)vec1_to_tuple<glm::i8>, METH_NOARGS, "Return the components of this vector as a tuple"},
+	{ "to_bytes", (PyCFunction)generic_to_bytes, METH_NOARGS, "Create a bytes string from this object"},
+	{ "from_bytes", (PyCFunction)vec_from_bytes<1, glm::i8>, METH_O | METH_STATIC, "Create a vector from a bytes string"},
 	{ NULL }  /* Sentinel */
 };
 static PyBufferProcs hi8vec1BufferMethods = {
diff --git a/PyGLM/types/vec/int8/vec2.h b/PyGLM/types/vec/int8/vec2.h
index 7befcd8..1522422 100644
--- a/PyGLM/types/vec/int8/vec2.h
+++ b/PyGLM/types/vec/int8/vec2.h
@@ -16,6 +16,8 @@ static PyMethodDef hi8vec2_methods[] = {
 	{ "__setstate__", (PyCFunction)vec2_setstate<glm::i8>, METH_O, "Restores a state that was previously acquired"},
 	{ "to_list", (PyCFunction)vec2_to_list<glm::i8>, METH_NOARGS, "Return the components of this vector as a list"},
 	{ "to_tuple", (PyCFunction)vec2_to_tuple<glm::i8>, METH_NOARGS, "Return the components of this vector as a tuple"},
+	{ "to_bytes", (PyCFunction)generic_to_bytes, METH_NOARGS, "Create a bytes string from this object"},
+	{ "from_bytes", (PyCFunction)vec_from_bytes<2, glm::i8>, METH_O | METH_STATIC, "Create a vector from a bytes string"},
 	{ NULL }  /* Sentinel */
 };
 static PyBufferProcs hi8vec2BufferMethods = {
diff --git a/PyGLM/types/vec/int8/vec3.h b/PyGLM/types/vec/int8/vec3.h
index 62740fd..c7737fb 100644
--- a/PyGLM/types/vec/int8/vec3.h
+++ b/PyGLM/types/vec/int8/vec3.h
@@ -17,6 +17,8 @@ static PyMethodDef hi8vec3_methods[] = {
 	{ "__setstate__", (PyCFunction)vec3_setstate<glm::i8>, METH_O, "Restores a state that was previously acquired"},
 	{ "to_list", (PyCFunction)vec3_to_list<glm::i8>, METH_NOARGS, "Return the components of this vector as a list"},
 	{ "to_tuple", (PyCFunction)vec3_to_tuple<glm::i8>, METH_NOARGS, "Return the components of this vector as a tuple"},
+	{ "to_bytes", (PyCFunction)generic_to_bytes, METH_NOARGS, "Create a bytes string from this object"},
+	{ "from_bytes", (PyCFunction)vec_from_bytes<3, glm::i8>, METH_O | METH_STATIC, "Create a vector from a bytes string"},
 	{ NULL }  /* Sentinel */
 };
 static PyBufferProcs hi8vec3BufferMethods = {
diff --git a/PyGLM/types/vec/int8/vec4.h b/PyGLM/types/vec/int8/vec4.h
index 94c2241..303a7eb 100644
--- a/PyGLM/types/vec/int8/vec4.h
+++ b/PyGLM/types/vec/int8/vec4.h
@@ -18,6 +18,8 @@ static PyMethodDef hi8vec4_methods[] = {
 	{ "__setstate__", (PyCFunction)vec4_setstate<glm::i8>, METH_O, "Restores a state that was previously acquired"},
 	{ "to_list", (PyCFunction)vec4_to_list<glm::i8>, METH_NOARGS, "Return the components of this vector as a list"},
 	{ "to_tuple", (PyCFunction)vec4_to_tuple<glm::i8>, METH_NOARGS, "Return the components of this vector as a tuple"},
+	{ "to_bytes", (PyCFunction)generic_to_bytes, METH_NOARGS, "Create a bytes string from this object"},
+	{ "from_bytes", (PyCFunction)vec_from_bytes<4, glm::i8>, METH_O | METH_STATIC, "Create a vector from a bytes string"},
 	{ NULL }  /* Sentinel */
 };
 static PyBufferProcs hi8vec4BufferMethods = {
diff --git a/PyGLM/types/vec/uint16/vec1.h b/PyGLM/types/vec/uint16/vec1.h
index ba26ef1..02bcd03 100644
--- a/PyGLM/types/vec/uint16/vec1.h
+++ b/PyGLM/types/vec/uint16/vec1.h
@@ -15,6 +15,8 @@ static PyMethodDef hu16vec1_methods[] = {
 	{ "__setstate__", (PyCFunction)vec1_setstate<glm::u16>, METH_O, "Restores a state that was previously acquired"},
 	{ "to_list", (PyCFunction)vec1_to_list<glm::u16>, METH_NOARGS, "Return the components of this vector as a list"},
 	{ "to_tuple", (PyCFunction)vec1_to_tuple<glm::u16>, METH_NOARGS, "Return the components of this vector as a tuple"},
+	{ "to_bytes", (PyCFunction)generic_to_bytes, METH_NOARGS, "Create a bytes string from this object"},
+	{ "from_bytes", (PyCFunction)vec_from_bytes<1, glm::u16>, METH_O | METH_STATIC, "Create a vector from a bytes string"},
 	{ NULL }  /* Sentinel */
 };
 static PyBufferProcs hu16vec1BufferMethods = {
diff --git a/PyGLM/types/vec/uint16/vec2.h b/PyGLM/types/vec/uint16/vec2.h
index 91fd582..8599dd4 100644
--- a/PyGLM/types/vec/uint16/vec2.h
+++ b/PyGLM/types/vec/uint16/vec2.h
@@ -16,6 +16,8 @@ static PyMethodDef hu16vec2_methods[] = {
 	{ "__setstate__", (PyCFunction)vec2_setstate<glm::u16>, METH_O, "Restores a state that was previously acquired"},
 	{ "to_list", (PyCFunction)vec2_to_list<glm::u16>, METH_NOARGS, "Return the components of this vector as a list"},
 	{ "to_tuple", (PyCFunction)vec2_to_tuple<glm::u16>, METH_NOARGS, "Return the components of this vector as a tuple"},
+	{ "to_bytes", (PyCFunction)generic_to_bytes, METH_NOARGS, "Create a bytes string from this object"},
+	{ "from_bytes", (PyCFunction)vec_from_bytes<2, glm::u16>, METH_O | METH_STATIC, "Create a vector from a bytes string"},
 	{ NULL }  /* Sentinel */
 };
 static PyBufferProcs hu16vec2BufferMethods = {
diff --git a/PyGLM/types/vec/uint16/vec3.h b/PyGLM/types/vec/uint16/vec3.h
index bfc3e59..4c97374 100644
--- a/PyGLM/types/vec/uint16/vec3.h
+++ b/PyGLM/types/vec/uint16/vec3.h
@@ -17,6 +17,8 @@ static PyMethodDef hu16vec3_methods[] = {
 	{ "__setstate__", (PyCFunction)vec3_setstate<glm::u16>, METH_O, "Restores a state that was previously acquired"},
 	{ "to_list", (PyCFunction)vec3_to_list<glm::u16>, METH_NOARGS, "Return the components of this vector as a list"},
 	{ "to_tuple", (PyCFunction)vec3_to_tuple<glm::u16>, METH_NOARGS, "Return the components of this vector as a tuple"},
+	{ "to_bytes", (PyCFunction)generic_to_bytes, METH_NOARGS, "Create a bytes string from this object"},
+	{ "from_bytes", (PyCFunction)vec_from_bytes<3, glm::u16>, METH_O | METH_STATIC, "Create a vector from a bytes string"},
 	{ NULL }  /* Sentinel */
 };
 static PyBufferProcs hu16vec3BufferMethods = {
diff --git a/PyGLM/types/vec/uint16/vec4.h b/PyGLM/types/vec/uint16/vec4.h
index e2e3613..335e616 100644
--- a/PyGLM/types/vec/uint16/vec4.h
+++ b/PyGLM/types/vec/uint16/vec4.h
@@ -18,6 +18,8 @@ static PyMethodDef hu16vec4_methods[] = {
 	{ "__setstate__", (PyCFunction)vec4_setstate<glm::u16>, METH_O, "Restores a state that was previously acquired"},
 	{ "to_list", (PyCFunction)vec4_to_list<glm::u16>, METH_NOARGS, "Return the components of this vector as a list"},
 	{ "to_tuple", (PyCFunction)vec4_to_tuple<glm::u16>, METH_NOARGS, "Return the components of this vector as a tuple"},
+	{ "to_bytes", (PyCFunction)generic_to_bytes, METH_NOARGS, "Create a bytes string from this object"},
+	{ "from_bytes", (PyCFunction)vec_from_bytes<4, glm::u16>, METH_O | METH_STATIC, "Create a vector from a bytes string"},
 	{ NULL }  /* Sentinel */
 };
 static PyBufferProcs hu16vec4BufferMethods = {
diff --git a/PyGLM/types/vec/uint32/vec1.h b/PyGLM/types/vec/uint32/vec1.h
index f203b20..7537f1b 100644
--- a/PyGLM/types/vec/uint32/vec1.h
+++ b/PyGLM/types/vec/uint32/vec1.h
@@ -15,6 +15,8 @@ static PyMethodDef huvec1_methods[] = {
 	{ "__setstate__", (PyCFunction)vec1_setstate<glm::u32>, METH_O, "Restores a state that was previously acquired"},
 	{ "to_list", (PyCFunction)vec1_to_list<glm::u32>, METH_NOARGS, "Return the components of this vector as a list"},
 	{ "to_tuple", (PyCFunction)vec1_to_tuple<glm::u32>, METH_NOARGS, "Return the components of this vector as a tuple"},
+	{ "to_bytes", (PyCFunction)generic_to_bytes, METH_NOARGS, "Create a bytes string from this object"},
+	{ "from_bytes", (PyCFunction)vec_from_bytes<1, glm::u32>, METH_O | METH_STATIC, "Create a vector from a bytes string"},
 	{ NULL }  /* Sentinel */
 };
 static PyBufferProcs huvec1BufferMethods = {
diff --git a/PyGLM/types/vec/uint32/vec2.h b/PyGLM/types/vec/uint32/vec2.h
index 52f2b8f..9e106ed 100644
--- a/PyGLM/types/vec/uint32/vec2.h
+++ b/PyGLM/types/vec/uint32/vec2.h
@@ -16,6 +16,8 @@ static PyMethodDef huvec2_methods[] = {
 	{ "__setstate__", (PyCFunction)vec2_setstate<glm::u32>, METH_O, "Restores a state that was previously acquired"},
 	{ "to_list", (PyCFunction)vec2_to_list<glm::u32>, METH_NOARGS, "Return the components of this vector as a list"},
 	{ "to_tuple", (PyCFunction)vec2_to_tuple<glm::u32>, METH_NOARGS, "Return the components of this vector as a tuple"},
+	{ "to_bytes", (PyCFunction)generic_to_bytes, METH_NOARGS, "Create a bytes string from this object"},
+	{ "from_bytes", (PyCFunction)vec_from_bytes<2, glm::u32>, METH_O | METH_STATIC, "Create a vector from a bytes string"},
 	{ NULL }  /* Sentinel */
 };
 static PyBufferProcs huvec2BufferMethods = {
diff --git a/PyGLM/types/vec/uint32/vec3.h b/PyGLM/types/vec/uint32/vec3.h
index 2fc7e51..5c3b10b 100644
--- a/PyGLM/types/vec/uint32/vec3.h
+++ b/PyGLM/types/vec/uint32/vec3.h
@@ -17,6 +17,8 @@ static PyMethodDef huvec3_methods[] = {
 	{ "__setstate__", (PyCFunction)vec3_setstate<glm::u32>, METH_O, "Restores a state that was previously acquired"},
 	{ "to_list", (PyCFunction)vec3_to_list<glm::u32>, METH_NOARGS, "Return the components of this vector as a list"},
 	{ "to_tuple", (PyCFunction)vec3_to_tuple<glm::u32>, METH_NOARGS, "Return the components of this vector as a tuple"},
+	{ "to_bytes", (PyCFunction)generic_to_bytes, METH_NOARGS, "Create a bytes string from this object"},
+	{ "from_bytes", (PyCFunction)vec_from_bytes<3, glm::u32>, METH_O | METH_STATIC, "Create a vector from a bytes string"},
 	{ NULL }  /* Sentinel */
 };
 static PyBufferProcs huvec3BufferMethods = {
diff --git a/PyGLM/types/vec/uint32/vec4.h b/PyGLM/types/vec/uint32/vec4.h
index 6dfcc2b..9c5824e 100644
--- a/PyGLM/types/vec/uint32/vec4.h
+++ b/PyGLM/types/vec/uint32/vec4.h
@@ -18,6 +18,8 @@ static PyMethodDef huvec4_methods[] = {
 	{ "__setstate__", (PyCFunction)vec4_setstate<glm::u32>, METH_O, "Restores a state that was previously acquired"},
 	{ "to_list", (PyCFunction)vec4_to_list<glm::u32>, METH_NOARGS, "Return the components of this vector as a list"},
 	{ "to_tuple", (PyCFunction)vec4_to_tuple<glm::u32>, METH_NOARGS, "Return the components of this vector as a tuple"},
+	{ "to_bytes", (PyCFunction)generic_to_bytes, METH_NOARGS, "Create a bytes string from this object"},
+	{ "from_bytes", (PyCFunction)vec_from_bytes<4, glm::u32>, METH_O | METH_STATIC, "Create a vector from a bytes string"},
 	{ NULL }  /* Sentinel */
 };
 static PyBufferProcs huvec4BufferMethods = {
diff --git a/PyGLM/types/vec/uint64/vec1.h b/PyGLM/types/vec/uint64/vec1.h
index 6a895ce..0067d12 100644
--- a/PyGLM/types/vec/uint64/vec1.h
+++ b/PyGLM/types/vec/uint64/vec1.h
@@ -15,6 +15,8 @@ static PyMethodDef hu64vec1_methods[] = {
 	{ "__setstate__", (PyCFunction)vec1_setstate<glm::u64>, METH_O, "Restores a state that was previously acquired"},
 	{ "to_list", (PyCFunction)vec1_to_list<glm::u64>, METH_NOARGS, "Return the components of this vector as a list"},
 	{ "to_tuple", (PyCFunction)vec1_to_tuple<glm::u64>, METH_NOARGS, "Return the components of this vector as a tuple"},
+	{ "to_bytes", (PyCFunction)generic_to_bytes, METH_NOARGS, "Create a bytes string from this object"},
+	{ "from_bytes", (PyCFunction)vec_from_bytes<1, glm::u64>, METH_O | METH_STATIC, "Create a vector from a bytes string"},
 	{ NULL }  /* Sentinel */
 };
 static PyBufferProcs hu64vec1BufferMethods = {
diff --git a/PyGLM/types/vec/uint64/vec2.h b/PyGLM/types/vec/uint64/vec2.h
index 9d56763..1258a43 100644
--- a/PyGLM/types/vec/uint64/vec2.h
+++ b/PyGLM/types/vec/uint64/vec2.h
@@ -16,6 +16,8 @@ static PyMethodDef hu64vec2_methods[] = {
 	{ "__setstate__", (PyCFunction)vec2_setstate<glm::u64>, METH_O, "Restores a state that was previously acquired"},
 	{ "to_list", (PyCFunction)vec2_to_list<glm::u64>, METH_NOARGS, "Return the components of this vector as a list"},
 	{ "to_tuple", (PyCFunction)vec2_to_tuple<glm::u64>, METH_NOARGS, "Return the components of this vector as a tuple"},
+	{ "to_bytes", (PyCFunction)generic_to_bytes, METH_NOARGS, "Create a bytes string from this object"},
+	{ "from_bytes", (PyCFunction)vec_from_bytes<2, glm::u64>, METH_O | METH_STATIC, "Create a vector from a bytes string"},
 	{ NULL }  /* Sentinel */
 };
 static PyBufferProcs hu64vec2BufferMethods = {
diff --git a/PyGLM/types/vec/uint64/vec3.h b/PyGLM/types/vec/uint64/vec3.h
index 56c8e83..ae97582 100644
--- a/PyGLM/types/vec/uint64/vec3.h
+++ b/PyGLM/types/vec/uint64/vec3.h
@@ -17,6 +17,8 @@ static PyMethodDef hu64vec3_methods[] = {
 	{ "__setstate__", (PyCFunction)vec3_setstate<glm::u64>, METH_O, "Restores a state that was previously acquired"},
 	{ "to_list", (PyCFunction)vec3_to_list<glm::u64>, METH_NOARGS, "Return the components of this vector as a list"},
 	{ "to_tuple", (PyCFunction)vec3_to_tuple<glm::u64>, METH_NOARGS, "Return the components of this vector as a tuple"},
+	{ "to_bytes", (PyCFunction)generic_to_bytes, METH_NOARGS, "Create a bytes string from this object"},
+	{ "from_bytes", (PyCFunction)vec_from_bytes<3, glm::u64>, METH_O | METH_STATIC, "Create a vector from a bytes string"},
 	{ NULL }  /* Sentinel */
 };
 static PyBufferProcs hu64vec3BufferMethods = {
diff --git a/PyGLM/types/vec/uint64/vec4.h b/PyGLM/types/vec/uint64/vec4.h
index 5ead3bb..287357c 100644
--- a/PyGLM/types/vec/uint64/vec4.h
+++ b/PyGLM/types/vec/uint64/vec4.h
@@ -18,6 +18,8 @@ static PyMethodDef hu64vec4_methods[] = {
 	{ "__setstate__", (PyCFunction)vec4_setstate<glm::u64>, METH_O, "Restores a state that was previously acquired"},
 	{ "to_list", (PyCFunction)vec4_to_list<glm::u64>, METH_NOARGS, "Return the components of this vector as a list"},
 	{ "to_tuple", (PyCFunction)vec4_to_tuple<glm::u64>, METH_NOARGS, "Return the components of this vector as a tuple"},
+	{ "to_bytes", (PyCFunction)generic_to_bytes, METH_NOARGS, "Create a bytes string from this object"},
+	{ "from_bytes", (PyCFunction)vec_from_bytes<4, glm::u64>, METH_O | METH_STATIC, "Create a vector from a bytes string"},
 	{ NULL }  /* Sentinel */
 };
 static PyBufferProcs hu64vec4BufferMethods = {
diff --git a/PyGLM/types/vec/uint8/vec1.h b/PyGLM/types/vec/uint8/vec1.h
index cf796ec..a3b6ab2 100644
--- a/PyGLM/types/vec/uint8/vec1.h
+++ b/PyGLM/types/vec/uint8/vec1.h
@@ -15,6 +15,8 @@ static PyMethodDef hu8vec1_methods[] = {
 	{ "__setstate__", (PyCFunction)vec1_setstate<glm::u8>, METH_O, "Restores a state that was previously acquired"},
 	{ "to_list", (PyCFunction)vec1_to_list<glm::u8>, METH_NOARGS, "Return the components of this vector as a list"},
 	{ "to_tuple", (PyCFunction)vec1_to_tuple<glm::u8>, METH_NOARGS, "Return the components of this vector as a tuple"},
+	{ "to_bytes", (PyCFunction)generic_to_bytes, METH_NOARGS, "Create a bytes string from this object"},
+	{ "from_bytes", (PyCFunction)vec_from_bytes<1, glm::u8>, METH_O | METH_STATIC, "Create a vector from a bytes string"},
 	{ NULL }  /* Sentinel */
 };
 static PyBufferProcs hu8vec1BufferMethods = {
diff --git a/PyGLM/types/vec/uint8/vec2.h b/PyGLM/types/vec/uint8/vec2.h
index 6a51596..0e5f74f 100644
--- a/PyGLM/types/vec/uint8/vec2.h
+++ b/PyGLM/types/vec/uint8/vec2.h
@@ -16,6 +16,8 @@ static PyMethodDef hu8vec2_methods[] = {
 	{ "__setstate__", (PyCFunction)vec2_setstate<glm::u8>, METH_O, "Restores a state that was previously acquired"},
 	{ "to_list", (PyCFunction)vec2_to_list<glm::u8>, METH_NOARGS, "Return the components of this vector as a list"},
 	{ "to_tuple", (PyCFunction)vec2_to_tuple<glm::u8>, METH_NOARGS, "Return the components of this vector as a tuple"},
+	{ "to_bytes", (PyCFunction)generic_to_bytes, METH_NOARGS, "Create a bytes string from this object"},
+	{ "from_bytes", (PyCFunction)vec_from_bytes<2, glm::u8>, METH_O | METH_STATIC, "Create a vector from a bytes string"},
 	{ NULL }  /* Sentinel */
 };
 static PyBufferProcs hu8vec2BufferMethods = {
diff --git a/PyGLM/types/vec/uint8/vec3.h b/PyGLM/types/vec/uint8/vec3.h
index faac7f3..8138962 100644
--- a/PyGLM/types/vec/uint8/vec3.h
+++ b/PyGLM/types/vec/uint8/vec3.h
@@ -17,6 +17,8 @@ static PyMethodDef hu8vec3_methods[] = {
 	{ "__setstate__", (PyCFunction)vec3_setstate<glm::u8>, METH_O, "Restores a state that was previously acquired"},
 	{ "to_list", (PyCFunction)vec3_to_list<glm::u8>, METH_NOARGS, "Return the components of this vector as a list"},
 	{ "to_tuple", (PyCFunction)vec3_to_tuple<glm::u8>, METH_NOARGS, "Return the components of this vector as a tuple"},
+	{ "to_bytes", (PyCFunction)generic_to_bytes, METH_NOARGS, "Create a bytes string from this object"},
+	{ "from_bytes", (PyCFunction)vec_from_bytes<3, glm::u8>, METH_O | METH_STATIC, "Create a vector from a bytes string"},
 	{ NULL }  /* Sentinel */
 };
 static PyBufferProcs hu8vec3BufferMethods = {
diff --git a/PyGLM/types/vec/uint8/vec4.h b/PyGLM/types/vec/uint8/vec4.h
index 4edaf3d..badd642 100644
--- a/PyGLM/types/vec/uint8/vec4.h
+++ b/PyGLM/types/vec/uint8/vec4.h
@@ -18,6 +18,8 @@ static PyMethodDef hu8vec4_methods[] = {
 	{ "__setstate__", (PyCFunction)vec4_setstate<glm::u8>, METH_O, "Restores a state that was previously acquired"},
 	{ "to_list", (PyCFunction)vec4_to_list<glm::u8>, METH_NOARGS, "Return the components of this vector as a list"},
 	{ "to_tuple", (PyCFunction)vec4_to_tuple<glm::u8>, METH_NOARGS, "Return the components of this vector as a tuple"},
+	{ "to_bytes", (PyCFunction)generic_to_bytes, METH_NOARGS, "Create a bytes string from this object"},
+	{ "from_bytes", (PyCFunction)vec_from_bytes<4, glm::u8>, METH_O | METH_STATIC, "Create a vector from a bytes string"},
 	{ NULL }  /* Sentinel */
 };
 static PyBufferProcs hu8vec4BufferMethods = {


Test patch:
diff --git a/PyGLM_test.py b/PyGLM_test.py
index 08f5685..b11b444 100644
--- a/PyGLM_test.py
+++ b/PyGLM_test.py
@@ -1073,6 +1073,26 @@ def test_to_tuple():
     assert arr.to_tuple() == (glm.mat4(), glm.mat4(2))
 #/to_tuple #
 
+# to/from_bytes #
+def test_to_from_bytes():
+    for obj in gen_obj("V_M_Q"):
+        assert type(obj).from_bytes(obj.to_bytes()) == obj, repr(obj)
+    for obj in gen_obj("#MV"):
+        assert obj.to_bytes() == bytes(obj), repr(obj)
+
+    for args in gen_args("VVV_MMM_QQQ"):
+        arr = glm.array(args)
+        assert arr.from_bytes(arr.to_bytes(), arr.element_type) == arr
+#/to/from_bytes #
+
+# reinterpret_cast #
+def test_reinterpret_cast():
+    arr = glm.array.zeros(8*3*3*4*4, glm.uint8)
+
+    for type_ in (vector_types + matrix_types + quat_types + ctypes_types):
+        assert arr.reinterpret_cast(type_).element_type == type_
+#/reinterpret_cast #
+
 # pickling #
 import os
 if (eval(os.environ.get("TEST_PICKLING", "True"))):