Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added some documentations to AsyncLock file #2627

Merged
merged 2 commits into from
Oct 5, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
97 changes: 94 additions & 3 deletions RxSwift/Concurrency/AsyncLock.swift
Original file line number Diff line number Diff line change
Expand Up @@ -29,16 +29,58 @@ final class AsyncLock<I: InvocableType>
private var isExecuting: Bool = false
private var hasFaulted: Bool = false

// lock {
/**
Locks the current instance, preventing other threads from modifying it until `unlock()` is called.

This method is used to create a critical section where only one thread is allowed to access the protected resources at a time.

Example usage:
```swift
let lock = AsyncLock<SomeAction>()
lock.lock()
// Critical section
lock.unlock()
```
*/
func lock() {
self._lock.lock()
}

/**
Unlocks the current instance, allowing other threads to access the protected resources.

This method is called after a `lock()` to release the critical section, ensuring that other waiting threads can proceed.

Example usage:
```swift
let lock = AsyncLock<SomeAction>()
lock.lock()
// Critical section
lock.unlock()
```
*/
func unlock() {
self._lock.unlock()
}
// }

// MARK: - Queue Methods

/**
Enqueues an action into the internal queue for deferred execution.

If no actions are currently being executed, the method returns the action for immediate execution. Otherwise, the action is enqueued for deferred execution when the lock is available.

- Parameter action: The action to enqueue.
- Returns: The action if it can be executed immediately, or `nil` if it has been enqueued.

Example usage:
```swift
let lock = AsyncLock<SomeAction>()
if let action = lock.enqueue(someAction) {
action.invoke() // Execute the action immediately if it's not deferred.
}
```
*/
private func enqueue(_ action: I) -> I? {
self.lock(); defer { self.unlock() }
if self.hasFaulted {
Expand All @@ -55,6 +97,19 @@ final class AsyncLock<I: InvocableType>
return action
}

/**
Dequeues the next action for execution, if available.

If the queue is empty, this method resets the `isExecuting` flag to indicate that no actions are currently being executed.

- Returns: The next action from the queue, or `nil` if the queue is empty.

Example usage:
```swift
let nextAction = lock.dequeue()
nextAction?.invoke() // Execute the next action if one is available.
```
*/
private func dequeue() -> I? {
self.lock(); defer { self.unlock() }
if !self.queue.isEmpty {
Expand All @@ -66,6 +121,19 @@ final class AsyncLock<I: InvocableType>
}
}

/**
Invokes the provided action, ensuring that actions are executed sequentially.

The first action is executed immediately if no other actions are currently running. If other actions are already in the queue, the new action is enqueued and executed sequentially after the current actions are completed.

- Parameter action: The action to be invoked.

Example usage:
```swift
let lock = AsyncLock<SomeAction>()
lock.invoke(someAction) // Invoke or enqueue the action.
```
*/
func invoke(_ action: I) {
let firstEnqueuedAction = self.enqueue(action)

Expand All @@ -88,11 +156,34 @@ final class AsyncLock<I: InvocableType>
}
}
}


// MARK: - Dispose Methods

/**
Disposes of the `AsyncLock` by clearing the internal queue and preventing further actions from being executed.

This method ensures that all pending actions are discarded, and the lock enters a faulted state where no new actions can be enqueued or executed.

Example usage:
```swift
let lock = AsyncLock<SomeAction>()
lock.dispose() // Clear the queue and prevent further actions.
```
*/
func dispose() {
self.synchronizedDispose()
}

/**
Synchronously disposes of the internal queue and marks the lock as faulted.

This method is typically used internally to handle disposal of the lock in a thread-safe manner.

Example usage:
```swift
lock.synchronized_dispose()
```
*/
func synchronized_dispose() {
self.queue = Queue(capacity: 0)
self.hasFaulted = true
Expand Down
110 changes: 102 additions & 8 deletions RxSwift/GroupedObservable.swift
Original file line number Diff line number Diff line change
Expand Up @@ -6,30 +6,124 @@
// Copyright © 2015 Krunoslav Zaher. All rights reserved.
//

/// Represents an observable sequence of elements that have a common key.
/// Represents an observable sequence of elements that share a common key.
/// `GroupedObservable` is typically created by the `groupBy` operator.
/// Each `GroupedObservable` instance represents a collection of elements
/// that are grouped by a specific key.
///
/// Example usage:
/// ```
/// let observable = Observable.of("Apple", "Banana", "Apricot", "Blueberry", "Avocado")
///
/// let grouped = observable.groupBy { fruit in
/// fruit.first! // Grouping by the first letter of each fruit
/// }
///
/// _ = grouped.subscribe { group in
/// print("Group: \(group.key)")
/// _ = group.subscribe { event in
/// print(event)
/// }
/// }
/// ```
/// This will print:
/// ```
/// Group: A
/// next(Apple)
/// next(Apricot)
/// next(Avocado)
/// Group: B
/// next(Banana)
/// next(Blueberry)
/// ```
public struct GroupedObservable<Key, Element> : ObservableType {
/// Gets the common key.
/// The key associated with this grouped observable sequence.
/// All elements emitted by this observable share this common key.
public let key: Key

private let source: Observable<Element>

/// Initializes grouped observable sequence with key and source observable sequence.
/// Initializes a grouped observable sequence with a key and a source observable sequence.
///
/// - parameter key: Grouped observable sequence key
/// - parameter source: Observable sequence that represents sequence of elements for the key
/// - returns: Grouped observable sequence of elements for the specific key
/// - Parameters:
/// - key: The key associated with this grouped observable sequence.
/// - source: The observable sequence of elements for the specified key.
///
/// Example usage:
/// ```
/// let sourceObservable = Observable.of("Apple", "Apricot", "Avocado")
/// let groupedObservable = GroupedObservable(key: "A", source: sourceObservable)
///
/// _ = groupedObservable.subscribe { event in
/// print(event)
/// }
/// ```
/// This will print:
/// ```
/// next(Apple)
/// next(Apricot)
/// next(Avocado)
/// ```
public init(key: Key, source: Observable<Element>) {
self.key = key
self.source = source
}

/// Subscribes `observer` to receive events for this sequence.
/// Subscribes an observer to receive events emitted by the source observable sequence.
///
/// - Parameter observer: The observer that will receive the events of the source observable.
/// - Returns: A `Disposable` representing the subscription, which can be used to cancel the subscription.
///
/// Example usage:
/// ```
/// let fruitsObservable = Observable.of("Apple", "Banana", "Apricot", "Blueberry", "Avocado")
/// let grouped = fruitsObservable.groupBy { $0.first! } // Group by first letter
///
/// _ = grouped.subscribe { group in
/// if group.key == "A" {
/// _ = group.subscribe { event in
/// print(event)
/// }
/// }
/// }
/// ```
/// This will print:
/// ```
/// next(Apple)
/// next(Apricot)
/// next(Avocado)
/// ```
public func subscribe<Observer: ObserverType>(_ observer: Observer) -> Disposable where Observer.Element == Element {
self.source.subscribe(observer)
}

/// Converts `self` to `Observable` sequence.
/// Converts this `GroupedObservable` into a regular `Observable` sequence.
/// This allows you to work with the sequence without directly interacting with the key.
///
/// - Returns: The underlying `Observable` sequence of elements for the specified key.
///
/// Example usage:
/// ```
/// let fruitsObservable = Observable.of("Apple", "Banana", "Apricot", "Blueberry", "Avocado")
/// let grouped = fruitsObservable.groupBy { $0.first! } // Group by first letter
///
/// _ = grouped.subscribe { group in
/// if group.key == "A" {
/// let regularObservable = group.asObservable()
/// _ = regularObservable.subscribe { event in
/// print(event)
/// }
/// }
/// }
/// ```
/// This will print:
/// ```
/// next(Apple)
/// next(Apricot)
/// next(Avocado)
/// ```
public func asObservable() -> Observable<Element> {
self.source
}
}

Loading