#     Copyright 2016, Kay Hayen, mailto:kay.hayen@gmail.com
#
#     Part of "Nuitka", an optimizing Python compiler that is compatible and
#     integrates with CPython, but also works on its own.
#
#     Licensed under the Apache License, Version 2.0 (the "License");
#     you may not use this file except in compliance with the License.
#     You may obtain a copy of the License at
#
#        http://www.apache.org/licenses/LICENSE-2.0
#
#     Unless required by applicable law or agreed to in writing, software
#     distributed under the License is distributed on an "AS IS" BASIS,
#     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
#     See the License for the specific language governing permissions and
#     limitations under the License.
#
""" Module to hide the complexity of using pickle.

It should be simple, but it is not yet. Not all the pickle modules are well behaved.
"""

import pickletools
from logging import warning

from nuitka import Constants
from nuitka.__past__ import unicode  # pylint: disable=W0622
from nuitka.PythonVersions import python_version

# Work around for CPython 3.x removal of "cpickle".
try:
    import cPickle as cpickle
except ImportError:
    import pickle as cpickle


if python_version >= 300:
    # Python3: The protocol 3 adds support for bytes type.
    pickle_protocol = 3
else:
    pickle_protocol = 2


def getStreamedConstant(constant_value):
    # Note: The marshal module cannot persist all unicode strings and
    # therefore cannot be used. Instead we use pickle.
    try:
        saved = cpickle.dumps(
            constant_value,
            protocol = 0 if type(constant_value) is unicode else pickle_protocol
        )
    except TypeError:
        warning("Problem with persisting constant '%r'." % constant_value)
        raise

    saved = pickletools.optimize(saved)

    # Check that the constant is restored correctly.
    try:
        restored = cpickle.loads(
            saved
        )
    except:
        warning("Problem with persisting constant '%r'." % constant_value)
        raise

    if not Constants.compareConstants(restored, constant_value):
        raise AssertionError(
            "Streaming of constant changed value",
            constant_value,
            "!=",
            restored,
            "types:",
            type(constant_value),
            type(restored)
        )

    return saved
