d
This commit is contained in:
1
Modules/BusX
Symbolic link
1
Modules/BusX
Symbolic link
@@ -0,0 +1 @@
|
||||
../../../../u/Modules/BusX
|
||||
@@ -1,31 +0,0 @@
|
||||
import Combine
|
||||
|
||||
public extension Bus {
|
||||
final class Async<Src, Dst> {
|
||||
let v = PassthroughSubject<Src, Never>()
|
||||
var subscriptions = [AnyCancellable]()
|
||||
|
||||
public init(
|
||||
_ handler: @escaping ((Src) -> Dst?),
|
||||
_ src: String,
|
||||
_ dst: String
|
||||
) {
|
||||
// Вход.
|
||||
Bus.receiveSync(
|
||||
[src],
|
||||
{ [weak self] _, v in self?.v.send(v) },
|
||||
&subscriptions
|
||||
)
|
||||
// Выход.
|
||||
Bus.sendSync(
|
||||
dst,
|
||||
v
|
||||
.compactMap { (v: Src) in handler(v) }
|
||||
// Асинхронно.
|
||||
.receive(on: DispatchQueue.main)
|
||||
.eraseToAnyPublisher(),
|
||||
&subscriptions
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,29 +0,0 @@
|
||||
public extension Bus {
|
||||
/// Пропускаем далее единственный ключ.
|
||||
static func convertKeyValue<T>(
|
||||
_ key: String,
|
||||
_ v: (key: String, value: Any)
|
||||
) -> (String, T)? {
|
||||
guard
|
||||
key == v.key,
|
||||
let value = v.value as? T
|
||||
else {
|
||||
return nil
|
||||
}
|
||||
return (key, value)
|
||||
}
|
||||
|
||||
/// Пропускаем далее множество ключей.
|
||||
static func convertKeyValue<T>(
|
||||
_ keys: Set<String>,
|
||||
_ v: (key: String, value: Any)
|
||||
) -> (String, T)? {
|
||||
guard
|
||||
keys.contains(v.key),
|
||||
let value = v.value as? T
|
||||
else {
|
||||
return nil
|
||||
}
|
||||
return (v.key, value)
|
||||
}
|
||||
}
|
||||
@@ -1,31 +0,0 @@
|
||||
import Combine
|
||||
|
||||
public extension Bus {
|
||||
final class Debounce<Src, Dst> {
|
||||
let v = PassthroughSubject<Src, Never>()
|
||||
var subscriptions = [AnyCancellable]()
|
||||
|
||||
public init(
|
||||
_ handler: @escaping ((Src) -> Dst?),
|
||||
_ sec: Double,
|
||||
_ src: String,
|
||||
_ dst: String
|
||||
) {
|
||||
// Вход.
|
||||
Bus.receiveSync(
|
||||
[src],
|
||||
{ [weak self] _, v in self?.v.send(v) },
|
||||
&subscriptions
|
||||
)
|
||||
// Выход.
|
||||
Bus.sendSync(
|
||||
dst,
|
||||
v
|
||||
.debounce(for: .seconds(sec), scheduler: DispatchQueue.main)
|
||||
.compactMap { (v: Src) in handler(v) }
|
||||
.eraseToAnyPublisher(),
|
||||
&subscriptions
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,31 +0,0 @@
|
||||
import Combine
|
||||
|
||||
public extension Bus {
|
||||
final class Delay<Src, Dst> {
|
||||
let v = PassthroughSubject<Src, Never>()
|
||||
var subscriptions = [AnyCancellable]()
|
||||
|
||||
public init(
|
||||
_ handler: @escaping ((Src) -> Dst?),
|
||||
_ sec: Double,
|
||||
_ src: String,
|
||||
_ dst: String
|
||||
) {
|
||||
// Вход.
|
||||
Bus.receiveSync(
|
||||
[src],
|
||||
{ [weak self] _, v in self?.v.send(v) },
|
||||
&subscriptions
|
||||
)
|
||||
// Выход.
|
||||
Bus.sendSync(
|
||||
dst,
|
||||
v
|
||||
.delay(for: .seconds(sec), scheduler: DispatchQueue.main)
|
||||
.compactMap { (v: Src) in handler(v) }
|
||||
.eraseToAnyPublisher(),
|
||||
&subscriptions
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,29 +0,0 @@
|
||||
import Combine
|
||||
|
||||
public extension Bus {
|
||||
final class Sync<Src, Dst> {
|
||||
let v = PassthroughSubject<Src, Never>()
|
||||
var subscriptions = [AnyCancellable]()
|
||||
|
||||
public init(
|
||||
_ handler: @escaping ((Src) -> Dst?),
|
||||
_ src: String,
|
||||
_ dst: String
|
||||
) {
|
||||
// Вход.
|
||||
Bus.receiveSync(
|
||||
[src],
|
||||
{ [weak self] _, v in self?.v.send(v) },
|
||||
&subscriptions
|
||||
)
|
||||
// Выход.
|
||||
Bus.sendSync(
|
||||
dst,
|
||||
v
|
||||
.compactMap { (v: Src) in handler(v) }
|
||||
.eraseToAnyPublisher(),
|
||||
&subscriptions
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,56 +0,0 @@
|
||||
import Combine
|
||||
import Foundation
|
||||
|
||||
public enum Bus {
|
||||
private static let e = PassthroughSubject<(key: String, value: Any), Never>()
|
||||
|
||||
public static var events: AnyPublisher<(key: String, value: Any), Never> {
|
||||
e.eraseToAnyPublisher()
|
||||
}
|
||||
}
|
||||
|
||||
public extension Bus {
|
||||
/// Асинхронно обрабатываем входящие события из шины.
|
||||
static func receiveAsync<T>(
|
||||
_ keys: Set<String>,
|
||||
_ handler: @escaping ((String, T) -> Void),
|
||||
_ subscriptions: inout [AnyCancellable]
|
||||
) {
|
||||
e
|
||||
.compactMap { convertKeyValue(keys, $0) }
|
||||
.receive(on: DispatchQueue.main)
|
||||
.sink { v in handler(v.0, v.1) }
|
||||
.store(in: &subscriptions)
|
||||
}
|
||||
|
||||
/// Синхронно обрабатываем входящие события из шины.
|
||||
static func receiveSync<T>(
|
||||
_ keys: Set<String>,
|
||||
_ handler: @escaping ((String, T) -> Void),
|
||||
_ subscriptions: inout [AnyCancellable]
|
||||
) {
|
||||
e
|
||||
.compactMap { convertKeyValue(keys, $0) }
|
||||
.sink { v in handler(v.0, v.1) }
|
||||
.store(in: &subscriptions)
|
||||
}
|
||||
|
||||
/// Синхронно отправляем события из узла в шину.
|
||||
///
|
||||
/// Для асинхронной отправки достаточно добавить оператор `receive(on:)`
|
||||
/// в цепочке параметра `node`
|
||||
static func sendSync<T>(
|
||||
_ key: String,
|
||||
_ node: AnyPublisher<T, Never>,
|
||||
_ subscriptions: inout [AnyCancellable]
|
||||
) {
|
||||
node
|
||||
.sink { v in e.send((key, v)) }
|
||||
.store(in: &subscriptions)
|
||||
}
|
||||
|
||||
/// Единоразово синхронно отправляем событие в шину.
|
||||
static func send(_ key: String, _ value: Any) {
|
||||
e.send((key, value))
|
||||
}
|
||||
}
|
||||
@@ -1,9 +0,0 @@
|
||||
extension BusUI {
|
||||
/// Пропускаем лишь значения от UI
|
||||
///
|
||||
/// - Returns: Значение без префиксов "a:"/"u:"
|
||||
static func onlyUIText(_ s: String) -> String? {
|
||||
guard s.hasPrefix("u:") else { return nil }
|
||||
return String(s.dropFirst(2))
|
||||
}
|
||||
}
|
||||
@@ -1,16 +0,0 @@
|
||||
import Combine
|
||||
|
||||
extension BusUI {
|
||||
public final class Button: ObservableObject {
|
||||
public let v = PassthroughSubject<Void, Never>()
|
||||
var subscriptions = [AnyCancellable]()
|
||||
|
||||
public init(_ key: String) {
|
||||
Bus.sendSync(
|
||||
key,
|
||||
v.map { true }.eraseToAnyPublisher(),
|
||||
&subscriptions
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,29 +0,0 @@
|
||||
import Combine
|
||||
import SwiftUI
|
||||
|
||||
extension BusUI {
|
||||
public final class TextField: ObservableObject {
|
||||
@Published public var v = "a:"
|
||||
var subscriptions = [AnyCancellable]()
|
||||
|
||||
public init(
|
||||
_ textApp: String,
|
||||
_ textUI: String
|
||||
) {
|
||||
Bus.sendSync(
|
||||
textUI,
|
||||
$v
|
||||
.removeDuplicates()
|
||||
.compactMap(onlyUIText)
|
||||
.eraseToAnyPublisher(),
|
||||
&subscriptions
|
||||
)
|
||||
|
||||
Bus.receiveSync(
|
||||
[textApp],
|
||||
{ [weak self] (_, v: String) in self?.v = "a:\(v)" },
|
||||
&subscriptions
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,22 +0,0 @@
|
||||
import Foundation
|
||||
|
||||
extension BusUI {
|
||||
public final class TextFieldSource: Formatter {
|
||||
/// Выдаём для отображения очищенную от источника строку.
|
||||
public override func string(for obj: Any?) -> String? {
|
||||
guard let str = obj as? String else { return nil }
|
||||
return String(str.dropFirst(2))
|
||||
}
|
||||
|
||||
/// Выдаём для использования кодом строку с указанием источника
|
||||
/// в виде пользователя `u:`
|
||||
public override func getObjectValue(
|
||||
_ obj: AutoreleasingUnsafeMutablePointer<AnyObject?>?,
|
||||
for string: String,
|
||||
errorDescription error: AutoreleasingUnsafeMutablePointer<NSString?>?
|
||||
) -> Bool {
|
||||
obj?.pointee = "u:\(string)" as AnyObject
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,20 +0,0 @@
|
||||
import Combine
|
||||
|
||||
extension BusUI {
|
||||
public final class Value<T>: ObservableObject {
|
||||
@Published public var v: T
|
||||
var subscriptions = [AnyCancellable]()
|
||||
|
||||
public init(
|
||||
_ key: String,
|
||||
_ defaultValue: T
|
||||
) {
|
||||
v = defaultValue
|
||||
Bus.receiveSync(
|
||||
[key],
|
||||
{ [weak self] (_, v: T) in self?.v = v },
|
||||
&subscriptions
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
public enum BusUI { }
|
||||
@@ -1,14 +0,0 @@
|
||||
Pod::Spec.new do |s|
|
||||
|
||||
s.name = 'BusX'
|
||||
s.version = '2023.12.30'
|
||||
s.license = 'IVCS'
|
||||
s.summary = 'Шина общения элементов приложения'
|
||||
s.homepage = 'IVCS'
|
||||
s.author = 'IVCS'
|
||||
s.source = { :git => 'https://fake.com/FAKE.git', :tag => s.version }
|
||||
s.source_files = '**/**/*.swift'
|
||||
s.swift_version = '5.2'
|
||||
s.ios.deployment_target = '14.0'
|
||||
|
||||
end
|
||||
@@ -1,6 +1,6 @@
|
||||
PODS:
|
||||
- AELog (0.6.3)
|
||||
- BusX (2023.12.30)
|
||||
- BusX (2024.01.15)
|
||||
- MeetupIdX (2023.12.31):
|
||||
- AELog
|
||||
- BusX
|
||||
@@ -27,7 +27,7 @@ EXTERNAL SOURCES:
|
||||
|
||||
SPEC CHECKSUMS:
|
||||
AELog: f732b70f7a9d1b4c6a3676304192b3908f362133
|
||||
BusX: d11e857e9cb762f649ee9f88fd5a4f8fbf5bf96b
|
||||
BusX: 1db5cf8652f7b206af468cc115cab3326efd1ced
|
||||
MeetupIdX: 2fa9fb27717aa8878ff495c1abe960c96e524308
|
||||
MPAKX: dc592434f55edf34709f6e4f37c9ec90dcd95185
|
||||
|
||||
|
||||
Reference in New Issue
Block a user