Skip to content

Commit

Permalink
#161 Add DataConvertible conformance to ATTFindByTypeResponse
Browse files Browse the repository at this point in the history
  • Loading branch information
colemancda committed Nov 7, 2024
1 parent 8614e3c commit 965fd04
Showing 1 changed file with 43 additions and 52 deletions.
95 changes: 43 additions & 52 deletions Sources/BluetoothGATT/ATTFindByTypeResponse.swift
Original file line number Diff line number Diff line change
Expand Up @@ -6,44 +6,43 @@
// Copyright © 2018 PureSwift. All rights reserved.
//

import Foundation
import Bluetooth

/// Find By Type Value Response
///
/// The *Find By Type Value Response* is sent in reply to a received *Find By Type Value Request*
/// and contains information about this server.
@frozen
public struct ATTFindByTypeResponse: ATTProtocolDataUnit, Equatable {
public struct ATTFindByTypeResponse: ATTProtocolDataUnit, Equatable, Hashable, Sendable {

public static var attributeOpcode: ATTOpcode { return .findByTypeResponse }
public static var attributeOpcode: ATTOpcode { .findByTypeResponse }

/// A list of 1 or more Handle Informations.
public var handles: [HandlesInformation]
public let handles: [HandlesInformation]

public init?(handles: [HandlesInformation]) {

guard handles.isEmpty == false
else { return nil }

self.handles = handles
}

internal init(_ handles: [HandlesInformation]) {

assert(handles.isEmpty == false, "Must have at least one HandlesInformation")
assert(handles.isEmpty == false, "Must have at least one element")
self.handles = handles
}
}

public extension ATTFindByTypeResponse {
// MARK: - DataConvertible

extension ATTFindByTypeResponse: DataConvertible {

/// Minimum length.
internal static var minimumLength: Int { return 1 + HandlesInformation.length }
internal static var minimumLength: Int { 1 + HandlesInformation.length }

init?(data: Data) {
public init?<Data: DataContainer>(data: Data) {

guard data.count >= type(of: self).minimumLength,
type(of: self).validateOpcode(data)
guard data.count >= Self.minimumLength,
Self.validateOpcode(data)
else { return nil }

let handleLength = HandlesInformation.length
Expand All @@ -57,36 +56,25 @@ public extension ATTFindByTypeResponse {

let handleIndices = (0 ..< handleCount)
let handles = handleIndices.map { (index: Int) -> HandlesInformation in

let byteIndex = 1 + (index * handleLength)
return HandlesInformation(data.subdataNoCopy(in: byteIndex ..< byteIndex + handleLength))
return HandlesInformation(data.subdata(in: byteIndex ..< byteIndex + handleLength))
}

self.init(handles: handles)
}

var data: Data {

return Data(self)
}
}

// MARK: - DataConvertible

extension ATTFindByTypeResponse: DataConvertible {

var dataLength: Int {

return 1 + (handles.count * HandlesInformation.length)
public func append<Data>(to data: inout Data) where Data : DataContainer {
data += Self.attributeOpcode.rawValue
data += self.handles
}

static func += <T: DataContainer> (data: inout T, value: ATTFindByTypeResponse) {

data += attributeOpcode.rawValue
value.handles.forEach { data += $0 }
public var dataLength: Int {
1 + (handles.count * HandlesInformation.length)
}
}

// MARK: - Supporting Types

public extension ATTFindByTypeResponse {

/// Handles Information
Expand All @@ -95,44 +83,47 @@ public extension ATTFindByTypeResponse {
/// a *Handles Information* shall be returned.
/// The *Found Attribute Handle* shall be set to the handle of the attribute that has the exact attribute type
/// and attribute value from the *Find By Type Value Request*.
struct HandlesInformation: Equatable {
struct HandlesInformation: Equatable, Hashable, Sendable {

/// Found Attribute Handle
public let foundAttribute: UInt16
public var foundAttribute: UInt16

/// Group End Handle
public let groupEnd: UInt16
public var groupEnd: UInt16

public init(foundAttribute: UInt16,
groupEnd: UInt16) {

public init(
foundAttribute: UInt16,
groupEnd: UInt16
) {
self.foundAttribute = foundAttribute
self.groupEnd = groupEnd
}
}
}

internal extension ATTFindByTypeResponse.HandlesInformation {
extension ATTFindByTypeResponse.HandlesInformation: DataConvertible {

static var length: Int { return 2 + 2 }
public static var length: Int { 4 }

init(_ data: Data) {

public init?<Data: DataContainer>(data: Data) {
guard data.count == Self.length else {
return nil
}
self.init(data)
}

internal init<Data: DataContainer>(_ data: Data) {
assert(data.count == Self.length)
self.foundAttribute = UInt16(littleEndian: UInt16(bytes: (data[0], data[1])))
self.groupEnd = UInt16(littleEndian: UInt16(bytes: (data[2], data[3])))
}
}

extension ATTFindByTypeResponse.HandlesInformation: DataConvertible {

var dataLength: Int {

return type(of: self).length
public func append<Data>(to data: inout Data) where Data : DataContainer {
data += foundAttribute.littleEndian
data += groupEnd.littleEndian
}

static func += <T: DataContainer> (data: inout T, value: ATTFindByTypeResponse.HandlesInformation) {

data += value.foundAttribute.littleEndian
data += value.groupEnd.littleEndian
public var dataLength: Int {
Self.length
}
}

0 comments on commit 965fd04

Please sign in to comment.