1# Copyright 2014 Google Inc. All rights reserved.
2#
3# Licensed under the Apache License, Version 2.0 (the "License");
4# you may not use this file except in compliance with the License.
5# You may obtain a copy of the License at
6#
7#     http://www.apache.org/licenses/LICENSE-2.0
8#
9# Unless required by applicable law or agreed to in writing, software
10# distributed under the License is distributed on an "AS IS" BASIS,
11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12# See the License for the specific language governing permissions and
13# limitations under the License.
14
15import collections
16import struct
17
18from . import packer
19from .compat import import_numpy, NumpyRequiredForThisFeature
20
21np = import_numpy()
22
23# For reference, see:
24# https://docs.python.org/2/library/ctypes.html#ctypes-fundamental-data-types-2
25
26# These classes could be collections.namedtuple instances, but those are new
27# in 2.6 and we want to work towards 2.5 compatability.
28
29class BoolFlags(object):
30    bytewidth = 1
31    min_val = False
32    max_val = True
33    py_type = bool
34    name = "bool"
35    packer_type = packer.boolean
36
37
38class Uint8Flags(object):
39    bytewidth = 1
40    min_val = 0
41    max_val = (2**8) - 1
42    py_type = int
43    name = "uint8"
44    packer_type = packer.uint8
45
46
47class Uint16Flags(object):
48    bytewidth = 2
49    min_val = 0
50    max_val = (2**16) - 1
51    py_type = int
52    name = "uint16"
53    packer_type = packer.uint16
54
55
56class Uint32Flags(object):
57    bytewidth = 4
58    min_val = 0
59    max_val = (2**32) - 1
60    py_type = int
61    name = "uint32"
62    packer_type = packer.uint32
63
64
65class Uint64Flags(object):
66    bytewidth = 8
67    min_val = 0
68    max_val = (2**64) - 1
69    py_type = int
70    name = "uint64"
71    packer_type = packer.uint64
72
73
74class Int8Flags(object):
75    bytewidth = 1
76    min_val = -(2**7)
77    max_val = (2**7) - 1
78    py_type = int
79    name = "int8"
80    packer_type = packer.int8
81
82
83class Int16Flags(object):
84    bytewidth = 2
85    min_val = -(2**15)
86    max_val = (2**15) - 1
87    py_type = int
88    name = "int16"
89    packer_type = packer.int16
90
91
92class Int32Flags(object):
93    bytewidth = 4
94    min_val = -(2**31)
95    max_val = (2**31) - 1
96    py_type = int
97    name = "int32"
98    packer_type = packer.int32
99
100
101class Int64Flags(object):
102    bytewidth = 8
103    min_val = -(2**63)
104    max_val = (2**63) - 1
105    py_type = int
106    name = "int64"
107    packer_type = packer.int64
108
109
110class Float32Flags(object):
111    bytewidth = 4
112    min_val = None
113    max_val = None
114    py_type = float
115    name = "float32"
116    packer_type = packer.float32
117
118
119class Float64Flags(object):
120    bytewidth = 8
121    min_val = None
122    max_val = None
123    py_type = float
124    name = "float64"
125    packer_type = packer.float64
126
127
128class SOffsetTFlags(Int32Flags):
129    pass
130
131
132class UOffsetTFlags(Uint32Flags):
133    pass
134
135
136class VOffsetTFlags(Uint16Flags):
137    pass
138
139
140def valid_number(n, flags):
141    if flags.min_val is None and flags.max_val is None:
142        return True
143    return flags.min_val <= n <= flags.max_val
144
145
146def enforce_number(n, flags):
147    if flags.min_val is None and flags.max_val is None:
148        return
149    if not flags.min_val <= n <= flags.max_val:
150        raise TypeError("bad number %s for type %s" % (str(n), flags.name))
151
152
153def float32_to_uint32(n):
154    packed = struct.pack("<1f", n)
155    (converted,) = struct.unpack("<1L", packed)
156    return converted
157
158
159def uint32_to_float32(n):
160    packed = struct.pack("<1L", n)
161    (unpacked,) = struct.unpack("<1f", packed)
162    return unpacked
163
164
165def float64_to_uint64(n):
166    packed = struct.pack("<1d", n)
167    (converted,) = struct.unpack("<1Q", packed)
168    return converted
169
170
171def uint64_to_float64(n):
172    packed = struct.pack("<1Q", n)
173    (unpacked,) = struct.unpack("<1d", packed)
174    return unpacked
175
176
177def to_numpy_type(number_type):
178    if np is not None:
179        return np.dtype(number_type.name).newbyteorder('<')
180    else:
181        raise NumpyRequiredForThisFeature('Numpy was not found.')
182