# Copyright (c) 2008 The Board of Trustees of The Leland Stanford Junior University
# Copyright (c) 2011, 2012 Open Networking Foundation
# Copyright (c) 2012, 2013 Big Switch Networks, Inc.
# See the file LICENSE.pyloxi which should have been included in the source distribution
"""
Utility functions independent of the protocol version
"""

# Automatically generated by LOXI from template generic_util.py
# Do not modify

import loxi
import struct

def unpack_list(reader, deserializer):
    """
    The deserializer function should take an OFReader and return the new object.
    """
    entries = []
    while not reader.is_empty():
        entries.append(deserializer(reader))
    return entries

def unpack_list_lv16(reader, deserializer):
    """
    The deserializer function should take an OFReader and return the new object.
    """
    def wrapper(reader):
        length, = reader.peek('!H')
        return deserializer(reader.slice(length))
    return unpack_list(reader, wrapper)

def unpack_list_tlv16(reader, deserializer):
    """
    The deserializer function should take an OFReader and an integer type
    and return the new object.
    """
    def wrapper(reader):
        typ, length, = reader.peek('!HH')
        return deserializer(reader.slice(length), typ)
    return unpack_list(reader, wrapper)

class OFReader(object):
    """
    Cursor over a read-only buffer

    OpenFlow messages are best thought of as a sequence of elements of
    variable size, rather than a C-style struct with fixed offsets and
    known field lengths. This class supports efficiently reading
    fields sequentially and is intended to be used recursively by the
    parsers of child objects which will implicitly update the offset.
    """
    def __init__(self, buf):
        self.buf = buf
        self.offset = 0

    def read(self, fmt):
        st = struct.Struct(fmt)
        if self.offset + st.size > len(self.buf):
            raise loxi.ProtocolError("Buffer too short")
        result = st.unpack_from(self.buf, self.offset)
        self.offset += st.size
        return result

    def read_all(self):
        buf = buffer(self.buf, self.offset)
        self.offset += len(buf)
        return str(buf)

    def peek(self, fmt):
        st = struct.Struct(fmt)
        if self.offset + st.size > len(self.buf):
            raise loxi.ProtocolError("Buffer too short")
        result = st.unpack_from(self.buf, self.offset)
        return result

    def skip(self, length):
        if self.offset + length > len(self.buf):
            raise loxi.ProtocolError("Buffer too short")
        self.offset += length

    def is_empty(self):
        return self.offset == len(self.buf)

    # Used when parsing variable length objects which have external length
    # fields (e.g. the actions list in an OF 1.0 packet-out message).
    def slice(self, length):
        if self.offset + length > len(self.buf):
            raise loxi.ProtocolError("Buffer too short")
        buf = OFReader(buffer(self.buf, self.offset, length))
        self.offset += length
        return buf
