1010
1111import Foundation
1212
13+ /// A container for the current subscribed channels and channel groups
1314struct SubscribeInput : Equatable {
14- private let channelEntries : [ String : PubNubChannel ]
15- private let groupEntries : [ String : PubNubChannel ]
16-
17- // swiftlint:disable:next large_tuple
18- typealias InsertingResult = (
19- newInput: SubscribeInput ,
20- insertedChannels: [ PubNubChannel ] ,
21- insertedGroups: [ PubNubChannel ]
22- )
23- // swiftlint:disable:next large_tuple
24- typealias RemovingResult = (
25- newInput: SubscribeInput ,
26- removedChannels: [ PubNubChannel ] ,
27- removedGroups: [ PubNubChannel ]
28- )
29-
30- init ( channels: [ PubNubChannel ] = [ ] , groups: [ PubNubChannel ] = [ ] ) {
31- self . channelEntries = channels. reduce ( into: [ String: PubNubChannel] ( ) ) { r, channel in
32- _ = r. insert ( channel)
33- }
34- self . groupEntries = groups. reduce ( into: [ String: PubNubChannel] ( ) ) { r, channel in
35- _ = r. insert ( channel)
36- }
37- }
38-
39- private init ( channels: [ String : PubNubChannel ] , groups: [ String : PubNubChannel ] ) {
40- self . channelEntries = channels
41- self . groupEntries = groups
42- }
43-
44- var isEmpty : Bool {
45- channelEntries. isEmpty && groupEntries. isEmpty
46- }
47-
48- var channels : [ PubNubChannel ] {
49- Array ( channelEntries. values)
50- }
51-
52- var groups : [ PubNubChannel ] {
53- Array ( groupEntries. values)
54- }
15+ private let subscribedChannels : Set < String >
16+ private let subscribedChannelGroups : Set < String >
5517
56- var subscribedChannelNames : [ String ] {
57- channelEntries. map { $0. key }
18+ /// Result of comparing two SubscribeInput instances
19+ struct Difference {
20+ /// Items that were added (present in new but not in old)
21+ let addedChannels : Set < String >
22+ /// Channels that were removed (present in old but not in new)
23+ let removedChannels : Set < String >
24+ /// Channel groups that were added (present in new but not in old)
25+ let addedChannelGroups : Set < String >
26+ /// Channel groups that were removed (present in old but not in new)
27+ let removedChannelGroups : Set < String >
5828 }
5929
60- var subscribedGroupNames : [ String ] {
61- groupEntries. map { $0. key }
30+ init ( channels: Set < String > = [ ] , channelGroups: Set < String > = [ ] ) {
31+ self . subscribedChannels = channels
32+ self . subscribedChannelGroups = channelGroups
6233 }
6334
64- var allSubscribedChannelNames : [ String ] {
65- channelEntries. reduce ( into: [ String] ( ) ) { result, entry in
66- result. append ( entry. value. id)
67- if entry. value. isPresenceSubscribed {
68- result. append ( entry. value. presenceId)
69- }
70- }
35+ init ( channels: [ String ] = [ ] , channelGroups: [ String ] = [ ] ) {
36+ self . subscribedChannels = Set ( channels)
37+ self . subscribedChannelGroups = Set ( channelGroups)
7138 }
7239
73- var allSubscribedGroupNames : [ String ] {
74- groupEntries. reduce ( into: [ String] ( ) ) { result, entry in
75- result. append ( entry. value. id)
76- if entry. value. isPresenceSubscribed {
77- result. append ( entry. value. presenceId)
78- }
79- }
40+ /// Whether the subscribe input is empty
41+ ///
42+ /// This is true if there are no subscribed channels or channel groups
43+ var isEmpty : Bool {
44+ subscribedChannels. isEmpty && subscribedChannelGroups. isEmpty
8045 }
8146
82- var presenceSubscribedChannelNames : [ String ] {
83- channelEntries. compactMap {
84- if $0. value. isPresenceSubscribed {
85- return $0. value. id
86- } else {
87- return nil
88- }
89- }
47+ /// Returns the names of all subscribed channels according to the `withPresence` parameter
48+ ///
49+ /// If `withPresence` is true, this list includes both regular and presence channel names
50+ /// If `withPresence` is false, this list does not include presence channel names
51+ func channelNames( withPresence: Bool ) -> [ String ] {
52+ withPresence ? subscribedChannels. allObjects : subscribedChannels. allObjects. filter { !$0. isPresenceChannelName }
9053 }
9154
92- var presenceSubscribedGroupNames : [ String ] {
93- groupEntries. compactMap {
94- if $0. value. isPresenceSubscribed {
95- return $0. value. id
96- } else {
97- return nil
98- }
99- }
55+ /// Returns the names of all subscribed channel groups according to the `withPresence` parameter
56+ ///
57+ /// If `withPresence` is true, this list includes both regular and presence channel group names
58+ /// If `withPresence` is false, this list does not include presence channel group names
59+ func channelGroupNames( withPresence: Bool ) -> [ String ] {
60+ withPresence ? subscribedChannelGroups. allObjects : subscribedChannelGroups. allObjects. filter { !$0. isPresenceChannelName }
10061 }
10162
63+ /// Total number of subscribed channels and channel groups
10264 var totalSubscribedCount : Int {
103- channelEntries . count + groupEntries . count
65+ subscribedChannels . count + subscribedChannelGroups . count
10466 }
10567
106- func adding(
107- channels: [ PubNubChannel ] ,
108- and groups: [ PubNubChannel ]
109- ) -> SubscribeInput . InsertingResult {
110- // Gets a copy of current channels and channel groups
111- var currentChannels = channelEntries
112- var currentGroups = groupEntries
113-
114- let insertedChannels = channels. filter { currentChannels. insert ( $0) }
115- let insertedGroups = groups. filter { currentGroups. insert ( $0) }
116-
117- return InsertingResult (
118- newInput: SubscribeInput ( channels: currentChannels, groups: currentGroups) ,
119- insertedChannels: insertedChannels,
120- insertedGroups: insertedGroups
68+ /// Adds the given channels and channel groups and returns a new input without modifying the current one
69+ func adding( channels: Set < String > , and channelGroups: Set < String > ) -> SubscribeInput {
70+ SubscribeInput (
71+ channels: channels. union ( subscribedChannels) ,
72+ channelGroups: channelGroups. union ( subscribedChannelGroups)
12173 )
12274 }
12375
124- func removing(
125- mainChannels: [ PubNubChannel ] ,
126- presenceChannelsOnly: [ PubNubChannel ] ,
127- mainGroups: [ PubNubChannel ] ,
128- presenceGroupsOnly: [ PubNubChannel ]
129- ) -> SubscribeInput . RemovingResult {
130- // Gets a copy of current channels and channel groups
131- var currentChannels = channelEntries
132- var currentGroups = groupEntries
133-
134- let removedChannels = mainChannels. compactMap {
135- currentChannels. removeValue ( forKey: $0. id)
136- } + presenceChannelsOnly. compactMap {
137- currentChannels. unsubscribePresence ( $0. id)
138- }
139- let removedGroups = mainGroups. compactMap {
140- currentGroups. removeValue ( forKey: $0. id)
141- } + presenceGroupsOnly. compactMap {
142- currentGroups. unsubscribePresence ( $0. id)
143- }
144- return RemovingResult (
145- newInput: SubscribeInput ( channels: currentChannels, groups: currentGroups) ,
146- removedChannels: removedChannels,
147- removedGroups: removedGroups
76+ /// Removes the given channels and channel groups and returns a new input without modifying the current one
77+ func removing( channels: Set < String > , and channelGroups: Set < String > ) -> SubscribeInput {
78+ SubscribeInput (
79+ channels: subscribedChannels. subtracting ( channels) ,
80+ channelGroups: subscribedChannelGroups. subtracting ( channelGroups)
14881 )
14982 }
15083
151- static func == ( lhs: SubscribeInput , rhs: SubscribeInput ) -> Bool {
152- let equalChannels = lhs. allSubscribedChannelNames. sorted ( by: < ) == rhs. allSubscribedChannelNames. sorted ( by: < )
153- let equalGroups = lhs. allSubscribedGroupNames. sorted ( by: < ) == rhs. allSubscribedGroupNames. sorted ( by: < )
84+ /// Compares this input with another and returns the differences
85+ func difference( from other: SubscribeInput ) -> Difference {
86+ let addedChannels = subscribedChannels. subtracting ( other. subscribedChannels)
87+ let removedChannels = other. subscribedChannels. subtracting ( subscribedChannels)
15488
155- return equalChannels && equalGroups
156- }
157- }
89+ let addedGroups = subscribedChannelGroups. subtracting ( other. subscribedChannelGroups)
90+ let removedGroups = other. subscribedChannelGroups. subtracting ( subscribedChannelGroups)
15891
159- extension Dictionary where Key == String , Value == PubNubChannel {
160- // Inserts and returns the provided channel if that channel doesn't already exist
161- mutating func insert( _ channel: Value ) -> Bool {
162- if let match = self [ channel. id] , match == channel {
163- return false
164- }
165- self [ channel. id] = channel
166- return true
92+ return Difference (
93+ addedChannels: addedChannels,
94+ removedChannels: removedChannels,
95+ addedChannelGroups: addedGroups,
96+ removedChannelGroups: removedGroups
97+ )
16798 }
16899
169- // Updates current Dictionary with the new channel value unsubscribed from Presence.
170- // Returns the updated value if the corresponding entry matching the passed `id:` was found, otherwise `nil`
171- @discardableResult mutating func unsubscribePresence( _ id: String ) -> Value ? {
172- if let match = self [ id] , match. isPresenceSubscribed {
173- let updatedChannel = PubNubChannel ( id: match. id, withPresence: false )
174- self [ match. id] = updatedChannel
175- return updatedChannel
176- }
177- return nil
100+ static func == ( lhs: SubscribeInput , rhs: SubscribeInput ) -> Bool {
101+ lhs. subscribedChannels == rhs. subscribedChannels && lhs. subscribedChannelGroups == rhs. subscribedChannelGroups
178102 }
179103}
180104
@@ -183,8 +107,8 @@ extension SubscribeInput: CustomStringConvertible {
183107 String . formattedDescription (
184108 self ,
185109 arguments: [
186- ( " channels " , allSubscribedChannelNames ) ,
187- ( " groups " , allSubscribedGroupNames )
110+ ( " channels " , channelNames ( withPresence : true ) ) ,
111+ ( " groups " , channelGroupNames ( withPresence : true ) )
188112 ]
189113 )
190114 }
0 commit comments