1# Copyright 2023 The Android Open Source Project
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
15from dataclasses import dataclass, field
16from typing import Tuple
17
18
19@dataclass(init=False)
20class Address:
21    address: bytes = field(default=bytes([0, 0, 0, 0, 0, 0]))
22
23    def __init__(self, address=None):
24        if not address:
25            self.address = bytes([0, 0, 0, 0, 0, 0])
26        elif isinstance(address, Address):
27            self.address = address.address
28        elif isinstance(address, str):
29            self.address = bytes([int(b, 16) for b in address.split(':')])
30        elif isinstance(address, (bytes, list)) and len(address) == 6:
31            self.address = bytes(address)
32        elif isinstance(address, bytes):
33            address = address.decode('utf-8')
34            self.address = bytes([int(b, 16) for b in address.split(':')])
35        else:
36            raise Exception(f'unsupported address type: {address}')
37
38    def parse(span: bytes) -> Tuple['Address', bytes]:
39        assert len(span) >= 6
40        return (Address(bytes(reversed(span[:6]))), span[6:])
41
42    def parse_all(span: bytes) -> 'Address':
43        assert len(span) == 6
44        return Address(bytes(reversed(span)))
45
46    def serialize(self) -> bytes:
47        return bytes(reversed(self.address))
48
49    def is_resolvable(self) -> bool:
50        return (self.address[0] & 0xc0) == 0x40
51
52    def is_non_resolvable(self) -> bool:
53        return (self.address[0] & 0xc0) == 0x00
54
55    def is_static_identity(self) -> bool:
56        return (self.address[0] & 0xc0) == 0xc0
57
58    def __repr__(self) -> str:
59        return ':'.join([f'{b:02x}' for b in self.address])
60
61    @property
62    def size(self) -> int:
63        return 6
64
65
66@dataclass
67class ClassOfDevice:
68    class_of_device: int = 0
69
70    def parse(span: bytes) -> Tuple['Address', bytes]:
71        assert len(span) >= 3
72        return (ClassOfDevice(int.from_bytes(span[:3], byteorder='little')), span[3:])
73
74    def parse_all(span: bytes) -> 'Address':
75        assert len(span) == 3
76        return ClassOfDevice(int.from_bytes(span, byteorder='little'))
77
78    def serialize(self) -> bytes:
79        return int.to_bytes(self.class_of_device, length=3, byteorder='little')
80
81    @property
82    def size(self) -> int:
83        return 3
84