Created
January 6, 2017 03:52
-
-
Save sanekgusev/475a8bf7d55a95aaf834652f3a6cad2d to your computer and use it in GitHub Desktop.
Robotized API
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// MARK: Interface | |
public protocol ConnectionState: RawRepresentable { | |
var rawValue: String { get } | |
init?(rawValue: String) | |
} | |
public struct SensorReading<U: Unit> { | |
let name: String | |
let measurement: Measurement<U> | |
} | |
extension SensorReading: Hashable { | |
public var hashValue: Int { | |
return name.hashValue ^ measurement.hashValue | |
} | |
} | |
public func ==<U>(lhs: SensorReading<U>, rhs: SensorReading<U>) -> Bool { | |
return lhs.name == rhs.name && lhs.measurement == rhs.measurement | |
} | |
public protocol CompoundSensorReading: Hashable { | |
var name: String { get } | |
var readings: Set<SensorReading<Unit>> { get } | |
} | |
extension CompoundSensorReading { | |
public var hashValue: Int { | |
return name.hashValue ^ readings.hashValue | |
} | |
} | |
public func ==<T: CompoundSensorReading>(lhs: T, rhs: T) -> Bool { | |
return lhs.name == rhs.name && lhs.readings == rhs.readings | |
} | |
public struct AnyCompoundSensorReading: CompoundSensorReading { | |
private let nameClosure: () -> String | |
private let readingsClosure: () -> Set<SensorReading<Unit>> | |
public init<CompoundSensorReadingType: CompoundSensorReading>(reading: CompoundSensorReadingType) { | |
nameClosure = { reading.name } | |
readingsClosure = { reading.readings } | |
} | |
public var name: String { | |
return nameClosure() | |
} | |
public var readings: Set<SensorReading<Unit>> { | |
return readingsClosure() | |
} | |
} | |
public protocol SensorSet { | |
var timestamp: Date { get } | |
var readings: Set<AnyCompoundSensorReading> { get } | |
} | |
public enum CommandArgumentValue<CustomArgumentType: Hashable, UnitType: Unit> { | |
case customType(CustomArgumentType) | |
case measurement(Measurement<UnitType>) | |
} | |
extension CommandArgumentValue: Hashable { | |
public var hashValue: Int { | |
switch self { | |
case let .customType(type): | |
return type.hashValue | |
case let .measurement(measurement): | |
return measurement.hashValue | |
} | |
} | |
} | |
public func ==<CustomArgumentType: Hashable, UnitType: Unit>(lhs: CommandArgumentValue<CustomArgumentType, UnitType>, rhs: CommandArgumentValue<CustomArgumentType, UnitType>) -> Bool { | |
switch (lhs, rhs) { | |
case let (.customType(t1), .customType(t2)) where t1 == t2: | |
return true | |
case let (.measurement(m1), .measurement(m2)) where m1 == m2: | |
return true | |
} | |
return false | |
} | |
public struct CommandArgument<CustomArgumentType: Hashable, UnitType: Unit> { | |
let name: String | |
let value: CommandArgumentValue<CustomArgumentType, UnitType> | |
} | |
extension CommandArgument: Hashable { | |
public var hashValue: Int { | |
return name.hashValue | |
} | |
} | |
public func ==<T, U: Unit>(lhs: CommandArgument<T, U>, rhs: CommandArgument<T, U>) -> Bool { | |
return lhs.name == rhs.name && lhs.value == rhs.value | |
} | |
public protocol Command: Hashable { | |
var name: String { get } | |
var arguments: Set<CommandArgument<AnyHashable, Unit>> { get } | |
} | |
extension Command { | |
public var hashValue: Int { | |
return name.hashValue ^ arguments.hashValue | |
} | |
} | |
public func ==<CommandType: Command>(lhs: CommandType, rhs: CommandType) -> Bool { | |
return lhs.name == rhs.name && lhs.arguments == rhs.arguments | |
} | |
public struct AnyCommand: Command { | |
private let nameClosure: () -> String | |
private let argumentsClosure: () -> Set<CommandArgument<AnyHashable, Unit>> | |
public init<CommandType: Command>(command: CommandType) { | |
nameClosure = { command.name } | |
argumentsClosure = { command.arguments } | |
} | |
public var name: String { | |
return nameClosure() | |
} | |
public var arguments: Set<CommandArgument<AnyHashable, Unit>> { | |
return argumentsClosure() | |
} | |
} | |
public protocol CommandSet { | |
var commands: Set<AnyCommand> { get } | |
} | |
public protocol Robot { | |
associatedtype SensorSetType: SensorSet | |
associatedtype ConnectionStateType: ConnectionState | |
associatedtype CommandSetType: CommandSet | |
var name: String { get } | |
var type: String { get } | |
var connectionState: ConnectionStateType { get } | |
var commands: CommandSetType { get } | |
var sensorHistory: AnyCollection<SensorSetType> { get } | |
} | |
// MARK: Implementation | |
public enum SampleConnectionState: String, ConnectionState { | |
case unknown | |
case lost | |
case discovered | |
case connecting | |
case connected | |
case disconnected | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
The idea is to create concrete implementations of
SensorSet
(with a bunch of specificCompoundSensorReading
implementations as its properties),ConnectionState
, andCommandSet
(with a bunch of specific commands as properties that all will conform toCommand
) for each implementation ofRobot
.Different models of robots would be represented by different
Robot
implementations.An
AnyRobot
type-erasing wrapper can also be created, in the same fashion asAnyCompoundSensorReading
andAnyCommand
, if at some point we'll need to treat different robots as being of same, more generic, type.This approach is also meant to make it easier to add support for new commands and sensor readings.
And yes, no callback/notification mechanism for now. 😞