import math import struct def convert_bytes_to_scalar(value: bytes) -> float: """ Convert byte array to scalar value (float64) Byte type is treated as base-256 value, considering at most 8 bytes Uses big-endian conversion Fully matches Golang's convertBytesToScalar function behavior """ # Create 8-byte buffer, initialized to 0 buf = bytearray(8) # Copy input bytes to buffer (at most 8 bytes) # This fully simulates Golang's copy(buf[:], value) behavior copy_len = min(len(value), 8) if copy_len > 0: buf[:copy_len] = value[:copy_len] # Use big-endian to convert to uint64, then to float64 uint64_val = struct.unpack(">Q", buf)[0] # '>' indicates big-endian return float(uint64_val) def convert_scalar_to_bytes(scalar: float, length: int = 8) -> bytes: """ Convert scalar value back to byte array (reverse conversion) """ if scalar < 0: scalar = 0 elif scalar > (2**64 - 1): scalar = 2**64 - 1 uint64_val = int(scalar) # Use big-endian to convert to 8 bytes full_bytes = struct.pack(">Q", uint64_val) # Return bytes of specified length if length >= 8: return full_bytes else: # Take specified length bytes from left (matches Golang's behavior) return full_bytes[:length] if length > 0 else b"" def common_prefix_length(*byte_arrays: bytes) -> int: """ Calculate common prefix length of multiple byte arrays Fully matches Golang's commonPrefixLength function """ if not byte_arrays: return 0 # Find the shortest array length min_len = min(len(arr) for arr in byte_arrays) # Compare byte by byte for i in range(min_len): first_byte = byte_arrays[0][i] for arr in byte_arrays[1:]: if arr[i] != first_byte: return i return min_len def calc_fraction(lower: float, upper: float, value: float) -> float: """ Calculate fractional position of value within interval Fully matches Golang's calcFraction function """ if upper <= lower: return 0.5 if value <= lower: return 0.0 if value >= upper: return 1.0 frac = (value - lower) / (upper - lower) # Check for invalid values if math.isnan(frac) or math.isinf(frac) or frac < 0 or frac > 1: return 0.5 return frac def convert_bytes_to_scalar_with_prefix(value: bytes, common_prefix_len: int) -> float: """ Convert bytes to scalar, skipping common prefix part Fully matches Golang's convertDatumToScalar handling of bytes """ if len(value) <= common_prefix_len: return 0.0 remaining_bytes = value[common_prefix_len:] return convert_bytes_to_scalar(remaining_bytes) def calc_fraction_for_bytes( lower_bytes: bytes, upper_bytes: bytes, value_bytes: bytes ) -> float: """ Calculate fraction for byte type, considering common prefix Fully matches Golang's calcFraction4Datums handling of bytes """ # Calculate common prefix length common_prefix_len = common_prefix_length(lower_bytes, upper_bytes) # Convert to scalar lower_scalar = convert_bytes_to_scalar_with_prefix(lower_bytes, common_prefix_len) upper_scalar = convert_bytes_to_scalar_with_prefix(upper_bytes, common_prefix_len) value_scalar = convert_bytes_to_scalar_with_prefix(value_bytes, common_prefix_len) return calc_fraction(lower_scalar, upper_scalar, value_scalar) class BytesScalarConverter: """ Bytes and scalar converter class, providing complete conversion functionality """ @staticmethod def bytes_to_float(data: bytes) -> float: """Convert bytes to float""" return convert_bytes_to_scalar(data) @staticmethod def float_to_bytes(value: float, length: int = 8) -> bytes: """Convert float to bytes""" return convert_scalar_to_bytes(value, length) @staticmethod def calc_position_fraction(lower: bytes, upper: bytes, value: bytes) -> float: """Calculate position fraction of value in byte interval""" return calc_fraction_for_bytes(lower, upper, value)