1 use async_trait::async_trait;
2 use bitflags::bitflags;
3 
4 use crate::{
5     core::uuid::Uuid,
6     gatt::ids::AttHandle,
7     packets::{AttErrorCode, AttHandleBuilder, AttHandleView},
8 };
9 
10 impl From<AttHandleView<'_>> for AttHandle {
from(value: AttHandleView) -> Self11     fn from(value: AttHandleView) -> Self {
12         AttHandle(value.get_handle())
13     }
14 }
15 
16 impl From<AttHandle> for AttHandleBuilder {
from(value: AttHandle) -> Self17     fn from(value: AttHandle) -> Self {
18         AttHandleBuilder { handle: value.0 }
19     }
20 }
21 
22 #[derive(Debug, Copy, Clone, PartialEq, Eq)]
23 pub struct AttAttribute {
24     pub handle: AttHandle,
25     pub type_: Uuid,
26     pub permissions: AttPermissions,
27 }
28 
29 bitflags! {
30     /// The attribute properties supported by the current GATT server implementation
31     /// Unimplemented properties will default to false.
32     ///
33     /// These values are from Core Spec 5.3 Vol 3G 3.3.1.1 Characteristic Properties,
34     /// and also match what Android uses in JNI.
35     #[derive(Copy, Clone, Debug, PartialEq, Eq)]
36     pub struct AttPermissions : u8 {
37         /// Attribute can be read using READ_REQ
38         const READABLE = 0x02;
39         /// Attribute can be written to using WRITE_CMD
40         const WRITABLE_WITHOUT_RESPONSE = 0x04;
41         /// Attribute can be written to using WRITE_REQ
42         const WRITABLE_WITH_RESPONSE = 0x08;
43         /// Attribute value may be sent using indications
44         const INDICATE = 0x20;
45     }
46 }
47 
48 impl AttPermissions {
49     /// Attribute can be read using READ_REQ
readable(&self) -> bool50     pub fn readable(&self) -> bool {
51         self.contains(AttPermissions::READABLE)
52     }
53     /// Attribute can be written to using WRITE_REQ
writable_with_response(&self) -> bool54     pub fn writable_with_response(&self) -> bool {
55         self.contains(AttPermissions::WRITABLE_WITH_RESPONSE)
56     }
57     /// Attribute can be written to using WRITE_CMD
writable_without_response(&self) -> bool58     pub fn writable_without_response(&self) -> bool {
59         self.contains(AttPermissions::WRITABLE_WITHOUT_RESPONSE)
60     }
61     /// Attribute value may be sent using indications
indicate(&self) -> bool62     pub fn indicate(&self) -> bool {
63         self.contains(AttPermissions::INDICATE)
64     }
65 }
66 
67 #[async_trait(?Send)]
68 pub trait AttDatabase {
69     /// Read an attribute by handle
read_attribute(&self, handle: AttHandle) -> Result<Vec<u8>, AttErrorCode>70     async fn read_attribute(&self, handle: AttHandle) -> Result<Vec<u8>, AttErrorCode>;
71 
72     /// Write to an attribute by handle
write_attribute(&self, handle: AttHandle, data: &[u8]) -> Result<(), AttErrorCode>73     async fn write_attribute(&self, handle: AttHandle, data: &[u8]) -> Result<(), AttErrorCode>;
74 
75     /// Write to an attribute by handle
write_no_response_attribute(&self, handle: AttHandle, data: &[u8])76     fn write_no_response_attribute(&self, handle: AttHandle, data: &[u8]);
77 
78     /// List all the attributes in this database.
79     ///
80     /// Expected to return them in sorted order.
list_attributes(&self) -> Vec<AttAttribute>81     fn list_attributes(&self) -> Vec<AttAttribute>;
82 
83     /// Produce an implementation of StableAttDatabase
snapshot(&self) -> SnapshottedAttDatabase<'_> where Self: Sized,84     fn snapshot(&self) -> SnapshottedAttDatabase<'_>
85     where
86         Self: Sized,
87     {
88         SnapshottedAttDatabase { attributes: self.list_attributes(), backing: self }
89     }
90 }
91 
92 /// Marker trait indicating that the backing attribute list of this
93 /// database is guaranteed to remain unchanged across async points.
94 ///
95 /// Useful if we want to call list_attributes() multiple times, rather than
96 /// caching its result the first time.
97 pub trait StableAttDatabase: AttDatabase {
find_attribute(&self, handle: AttHandle) -> Option<AttAttribute>98     fn find_attribute(&self, handle: AttHandle) -> Option<AttAttribute> {
99         self.list_attributes().into_iter().find(|attr| attr.handle == handle)
100     }
101 }
102 
103 /// A snapshot of an AttDatabase implementing StableAttDatabase.
104 pub struct SnapshottedAttDatabase<'a> {
105     attributes: Vec<AttAttribute>,
106     backing: &'a (dyn AttDatabase),
107 }
108 
109 #[async_trait(?Send)]
110 impl AttDatabase for SnapshottedAttDatabase<'_> {
read_attribute(&self, handle: AttHandle) -> Result<Vec<u8>, AttErrorCode>111     async fn read_attribute(&self, handle: AttHandle) -> Result<Vec<u8>, AttErrorCode> {
112         self.backing.read_attribute(handle).await
113     }
114 
write_attribute(&self, handle: AttHandle, data: &[u8]) -> Result<(), AttErrorCode>115     async fn write_attribute(&self, handle: AttHandle, data: &[u8]) -> Result<(), AttErrorCode> {
116         self.backing.write_attribute(handle, data).await
117     }
118 
write_no_response_attribute(&self, handle: AttHandle, data: &[u8])119     fn write_no_response_attribute(&self, handle: AttHandle, data: &[u8]) {
120         self.backing.write_no_response_attribute(handle, data);
121     }
122 
list_attributes(&self) -> Vec<AttAttribute>123     fn list_attributes(&self) -> Vec<AttAttribute> {
124         self.attributes.clone()
125     }
126 }
127 
128 impl StableAttDatabase for SnapshottedAttDatabase<'_> {}
129