@classmethod
def serialize(cls, value):
    """
        Converts value to something serializable by :mod:`json`.

        :param value: value to convert
        :return: :mod:`json` serializable equivalent

        By default, returns ``value``, to pass straight to :mod:`json`

        .. warning::

            :meth:`serialize` and :meth:`deserialize` **are not** symetrical.


        **Example of serializing then deserializing a custom object**

        Let's create our own ``Color`` class we'd like to represent as a
        parameter.

        .. doctest::

            >>> class Color(object):
            ...     def __init__(self, r, g, b):
            ...         self.r = r
            ...         self.g = g
            ...         self.b = b
            ...
            ...     def __eq__(self, other):
            ...         return (
            ...             type(self) == type(other) and \\
            ...             self.r == other.r and \\
            ...             self.g == other.g and \\
            ...             self.b == other.b
            ...         )
            ...
            ...     def __repr__(self):
            ...         return "<Color: %i, %i, %i>" % (self.r, self.g, self.b)

            >>> from cqparts.params import Parameter
            >>> class ColorParam(Parameter):
            ...     _doc_type = ":class:`list`"  # for sphinx documentation
            ...     def type(self, value):
            ...         (r, g, b) = value
            ...         return Color(r, g, b)
            ...
            ...     @classmethod
            ...     def serialize(cls, value):
            ...         # the default serialize will fail, we know this
            ...         # because json.dumps(Color(0,0,0)) raises an exception
            ...         if value is None:  # parameter is nullable
            ...             return None
            ...         return [value.r, value.g, value.b]
            ...
            ...     @classmethod
            ...     def deserialize(cls, value):
            ...         # the de-serialized rgb list is good to pass to type
            ...         return value

        Note that ``json_deserialize`` does not return a ``Color`` instance.
        Intead, it returns a *list* to be used as an input to :meth:`cast`
        (which is ultimately passed to :meth:`type`)

        This is because when the values are deserialized, they're used as the
        default values for a newly created :class:`ParametricObject <cqparts.params.parametric_object.ParametricObject>` class.

        So now when we use them in a :class:`ParametricObject <cqparts.params.parametric_object.ParametricObject>`:

        .. doctest::

            >>> from cqparts.params import ParametricObject, Float
            >>> class MyObject(ParametricObject):
            ...     color = ColorParam(default=[127, 127, 127])  # default 50% grey
            ...     height = Float(10)

            >>> my_object = MyObject(color=[100, 200, 255])
            >>> my_object.color  # is a Color instance (not a list)
            <Color: 100, 200, 255>

        Now to demonstrate how a parameter goes in and out of being serialized,
        we'll create a ``test`` method that, doesn't do anything, except that
        it should *not* throw any exceptions from its assertions, or the call
        to :meth:`json.dumps`

        .. doctest::

            >>> import json

            >>> def test(value, obj_class=Color, param_class=ColorParam):
            ...     orig_obj = param_class().cast(value)
            ...
            ...     # serialize
            ...     if value is None:
            ...         assert orig_obj == None
            ...     else:
            ...         assert isinstance(orig_obj, obj_class)
            ...     serialized = json.dumps(param_class.serialize(orig_obj))
            ...
            ...     # show serialized value
            ...     print(serialized)  # as a json string
            ...
            ...     # deserialize
            ...     ds_value = param_class.deserialize(json.loads(serialized))
            ...     new_obj = param_class().cast(ds_value)
            ...
            ...     # now orig_obj and new_obj should be identical
            ...     assert orig_obj == new_obj
            ...     print("all good")

            >>> test([1, 2, 3])
            [1, 2, 3]
            all good
            >>> test(None)
            null
            all good

        These are used to serialize and deserialize :class:`ParametricObject <cqparts.params.parametric_object.ParametricObject>`
        instances, so they may be added to a catalogue, then re-created.

        To learn more, go to :meth:`ParametricObject.serialize() <cqparts.params.parametric_object.ParametricObject.serialize>`

        """
    return value
