Skip to content

Commit

Permalink
#40: Added .initializeNow() to LazyContainer
Browse files Browse the repository at this point in the history
Implemented it everywhere in this package, added tests.

Also moved tests to the proper folder.
  • Loading branch information
KyNorthstar committed Dec 27, 2024
1 parent 60e6ed8 commit 3ffb734
Show file tree
Hide file tree
Showing 14 changed files with 235 additions and 12 deletions.
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,3 +42,6 @@ Initial movement from 4.x.

- Transitioned to Swift Testing
- Removed `LinuxMain.swift` & `XCTestManifests.swift` from tests since they're no longer needed

- Introduced `.initializeNow()`
- https://github.com/RougeWare/Swift-Lazy-Containers/issues/40
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,11 @@ public struct FunctionalLazy<Value>: LazyContainer {
public var isInitialized: Bool { _guts.isInitialized }


public mutating func initializeNow() {
_guts.initializeNow()
}



/// The actual functionality of `FunctionalLazy`, separated so that the semantics work out better
@propertyWrapper
Expand Down Expand Up @@ -114,6 +119,11 @@ public struct FunctionalLazy<Value>: LazyContainer {
set { initializer = { newValue } }
}


func initializeNow() {
_ = initializer()
}


/// Indicates whether the value has indeed been initialized
public var isInitialized: Bool { nil == semaphore }
Expand Down
25 changes: 20 additions & 5 deletions Sources/LazyContainers/Lazy.swift → Sources/Lazy/Lazy.swift
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,11 @@ public struct Lazy<Value>: LazyContainer {

/// Privatizes the inner-workings of this functional lazy container
@ValueReference
private var guts: ValueHolder<Value>
private var guts: ValueHolder


/// Allows other initializers to have a shared point of initialization
private init(_guts: ValueReference<ValueHolder<Value>>) {
private init(_guts: ValueReference<ValueHolder>) {
self._guts = _guts
}

Expand Down Expand Up @@ -73,6 +73,11 @@ public struct Lazy<Value>: LazyContainer {

/// Indicates whether the value has indeed been initialized
public var isInitialized: Bool { _guts.wrappedValue.hasValue }


public mutating func initializeNow() {
guts.initializeNow()
}
}


Expand Down Expand Up @@ -120,6 +125,18 @@ public enum LazyContainerValueHolder<Value> {
case .unset(initializer: _): return false
}
}


/// Immediately initializes the value held inside this value holder
///
/// If this holder already contains a value, this does nothing
mutating func initializeNow() {
switch self {
case .hasValue(_): return
case .unset(let initializer):
self = .hasValue(value: initializer())
}
}
}


Expand All @@ -128,7 +145,5 @@ public enum LazyContainerValueHolder<Value> {
public extension LazyContainer {

/// Takes care of keeping track of the state, value, and initializer as needed
///
/// - Attention: This will change in version 5, to be an alias to `LazyContainerValueHolder<Value>`
typealias ValueHolder = LazyContainerValueHolder
typealias ValueHolder = LazyContainerValueHolder<Value>
}
File renamed without changes.
File renamed without changes.
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,13 @@ public protocol LazyContainer {
var isInitialized: Bool { get }


/// Immediately initializes the value held inside this lazy container
///
/// If this holder already contains a value, this does nothing
// https://github.com/RougeWare/Swift-Lazy-Containers/issues/40
mutating func initializeNow()


/// Creates a lazy container that already contains an initialized value.
///
/// This is useful when you need a uniform API (for instance, when implementing a protocol that requires a `Lazy`),
Expand Down Expand Up @@ -68,7 +75,5 @@ public final class LazyContainerValueReference<Value> {
public extension LazyContainer {

/// Allows you to use reference semantics to hold a value inside a lazy container.
///
/// - Attention: This will change in version 5, to be an alias to `LazyContainerValueReference<Value>`
typealias ValueReference = LazyContainerValueReference
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,11 @@ public struct ResettableLazy<Value>: LazyContainer {

/// Privatizes the inner-workings of this functional lazy container
@ValueReference
private var guts: ResettableValueHolder<Value>
private var guts: ResettableValueHolder


/// Allows other initializers to have a shared point of initialization
private init(_guts: ValueReference<ResettableValueHolder<Value>>) {
private init(_guts: ValueReference<ResettableValueHolder>) {
self._guts = _guts
}

Expand Down Expand Up @@ -80,6 +80,11 @@ public struct ResettableLazy<Value>: LazyContainer {
public var isInitialized: Bool { _guts.wrappedValue.hasValue }


public mutating func initializeNow() {
guts.initializeNow()
}


/// Resets this lazy structure back to its unset state. Next time a value is needed, it will be regenerated using
/// the initializer given by the constructor
public func clear() {
Expand Down Expand Up @@ -147,6 +152,18 @@ public enum LazyContainerResettableValueHolder<Value> {
case .unset(initializer: _): return false
}
}


/// Immediately initializes the value in this holder.
///
/// If this holder already contains a value, this does nothing
public mutating func initializeNow() {
switch self {
case .hasValue(value: _, initializer: _): return
case .unset(let initializer):
self = .hasValue(value: initializer(), initializer: initializer)
}
}
}


Expand All @@ -156,7 +173,5 @@ public enum LazyContainerResettableValueHolder<Value> {
public extension LazyContainer {

/// Takes care of keeping track of the state, value, and initializer as needed
///
/// - Attention: This will change in version 5, to be an alias to `LazyContainerResettableValueHolder<Value>`
typealias ResettableValueHolder = LazyContainerResettableValueHolder
typealias ResettableValueHolder = LazyContainerResettableValueHolder<Value>
}
File renamed without changes.
File renamed without changes.
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,66 @@ struct LazyContainersTests {



// MARK: .initializeNow()

// https://github.com/RougeWare/Swift-Lazy-Containers/issues/40

@Test
mutating func initializeNow_Lazy_traditional() {
#expect(false == lazyInitTraditionally.isInitialized)
lazyInitTraditionally.initializeNow()
#expect(true == lazyInitTraditionally.isInitialized)
#expect("lazy B" == lazyInitTraditionally.wrappedValue)
#expect(true == lazyInitTraditionally.isInitialized)
#expect("lazy B" == lazyInitTraditionally.wrappedValue)
#expect(true == lazyInitTraditionally.isInitialized)

lazyInitTraditionally.wrappedValue = "Manual B"

#expect(true == lazyInitTraditionally.isInitialized)
#expect("Manual B" == lazyInitTraditionally.wrappedValue)
#expect(true == lazyInitTraditionally.isInitialized)
#expect("Manual B" == lazyInitTraditionally.wrappedValue)
#expect(true == lazyInitTraditionally.isInitialized)
#expect("Manual B" == lazyInitTraditionally.wrappedValue)
#expect(true == lazyInitTraditionally.isInitialized)
}


@Test
mutating func initializeNow_Lazy_customInitWithSideEffect() {
#expect(sideEffectA == nil)
#expect(false == _lazyInitWithPropertyWrapperAndCustomInitializerWithSideEffect.isInitialized)
#expect(sideEffectA == nil)
_lazyInitWithPropertyWrapperAndCustomInitializerWithSideEffect.initializeNow()
#expect(true == _lazyInitWithPropertyWrapperAndCustomInitializerWithSideEffect.isInitialized)
#expect(sideEffectA == "Side effect A1")
#expect("lAzy" == lazyInitWithPropertyWrapperAndCustomInitializerWithSideEffect)
#expect(sideEffectA == "Side effect A1")
#expect(true == _lazyInitWithPropertyWrapperAndCustomInitializerWithSideEffect.isInitialized)
#expect(sideEffectA == "Side effect A1")
#expect("lAzy" == lazyInitWithPropertyWrapperAndCustomInitializerWithSideEffect)
#expect(sideEffectA == "Side effect A1")
#expect(true == _lazyInitWithPropertyWrapperAndCustomInitializerWithSideEffect.isInitialized)
#expect(sideEffectA == "Side effect A1")

lazyInitWithPropertyWrapperAndCustomInitializerWithSideEffect = "MAnual"

#expect(sideEffectA == "Side effect A1")
#expect(true == _lazyInitWithPropertyWrapperAndCustomInitializerWithSideEffect.isInitialized)
#expect(sideEffectA == "Side effect A1")
#expect("MAnual" == lazyInitWithPropertyWrapperAndCustomInitializerWithSideEffect)
#expect(sideEffectA == "Side effect A1")
#expect(true == _lazyInitWithPropertyWrapperAndCustomInitializerWithSideEffect.isInitialized)
#expect(sideEffectA == "Side effect A1")
#expect("MAnual" == lazyInitWithPropertyWrapperAndCustomInitializerWithSideEffect)
#expect(sideEffectA == "Side effect A1")
#expect(true == _lazyInitWithPropertyWrapperAndCustomInitializerWithSideEffect.isInitialized)
#expect(sideEffectA == "Side effect A1")
}



// MARK: - `ResettableLazy`

@Test
Expand Down Expand Up @@ -209,6 +269,73 @@ struct LazyContainersTests {
#expect(true == resettableLazyInitTraditionally.isInitialized)
}

// MARK: .initializeNow()

// https://github.com/RougeWare/Swift-Lazy-Containers/issues/40

@Test
mutating func initializeNow_ResettableLazy_propertyWrapper() {
#expect(false == _resettableLazyInitWithPropertyWrapper.isInitialized)
_resettableLazyInitWithPropertyWrapper.initializeNow()
#expect(true == _resettableLazyInitWithPropertyWrapper.isInitialized)
#expect("lazy C" == resettableLazyInitWithPropertyWrapper)
#expect(true == _resettableLazyInitWithPropertyWrapper.isInitialized)
#expect("lazy C" == resettableLazyInitWithPropertyWrapper)
#expect(true == _resettableLazyInitWithPropertyWrapper.isInitialized)

resettableLazyInitWithPropertyWrapper = "Manual C"

#expect(true == _resettableLazyInitWithPropertyWrapper.isInitialized)
#expect("Manual C" == resettableLazyInitWithPropertyWrapper)
#expect(true == _resettableLazyInitWithPropertyWrapper.isInitialized)
#expect("Manual C" == resettableLazyInitWithPropertyWrapper)
#expect(true == _resettableLazyInitWithPropertyWrapper.isInitialized)
#expect("Manual C" == resettableLazyInitWithPropertyWrapper)
#expect(true == _resettableLazyInitWithPropertyWrapper.isInitialized)

_resettableLazyInitWithPropertyWrapper.clear()

#expect(false == _resettableLazyInitWithPropertyWrapper.isInitialized)
#expect("lazy C" == resettableLazyInitWithPropertyWrapper)
#expect(true == _resettableLazyInitWithPropertyWrapper.isInitialized)
#expect("lazy C" == resettableLazyInitWithPropertyWrapper)
#expect(true == _resettableLazyInitWithPropertyWrapper.isInitialized)
#expect("lazy C" == resettableLazyInitWithPropertyWrapper)
#expect(true == _resettableLazyInitWithPropertyWrapper.isInitialized)
}


@Test
mutating func initializeNow_ResettableLazy_traditional() {
#expect(false == resettableLazyInitTraditionally.isInitialized)
resettableLazyInitTraditionally.initializeNow()
#expect(true == resettableLazyInitTraditionally.isInitialized)
#expect("lazy D" == resettableLazyInitTraditionally.wrappedValue)
#expect(true == resettableLazyInitTraditionally.isInitialized)
#expect("lazy D" == resettableLazyInitTraditionally.wrappedValue)
#expect(true == resettableLazyInitTraditionally.isInitialized)

resettableLazyInitTraditionally.wrappedValue = "Manual D"

#expect(true == resettableLazyInitTraditionally.isInitialized)
#expect("Manual D" == resettableLazyInitTraditionally.wrappedValue)
#expect(true == resettableLazyInitTraditionally.isInitialized)
#expect("Manual D" == resettableLazyInitTraditionally.wrappedValue)
#expect(true == resettableLazyInitTraditionally.isInitialized)
#expect("Manual D" == resettableLazyInitTraditionally.wrappedValue)
#expect(true == resettableLazyInitTraditionally.isInitialized)

resettableLazyInitTraditionally.clear()

#expect(false == resettableLazyInitTraditionally.isInitialized)
#expect("lazy D" == resettableLazyInitTraditionally.wrappedValue)
#expect(true == resettableLazyInitTraditionally.isInitialized)
#expect("lazy D" == resettableLazyInitTraditionally.wrappedValue)
#expect(true == resettableLazyInitTraditionally.isInitialized)
#expect("lazy D" == resettableLazyInitTraditionally.wrappedValue)
#expect(true == resettableLazyInitTraditionally.isInitialized)
}



// MARK: - `FuctionalLazy`
Expand Down Expand Up @@ -255,4 +382,52 @@ struct LazyContainersTests {
#expect("Manual F" == functionalLazyInitTraditionally.wrappedValue)
#expect(true == functionalLazyInitTraditionally.isInitialized)
}


// MARK: .initializeNow()

// https://github.com/RougeWare/Swift-Lazy-Containers/issues/40

@Test
mutating func initializeNow_FunctionalLazy_propertyWrapper() {
#expect(false == _functionalLazyInitWithPropertyWrapper.isInitialized)
_functionalLazyInitWithPropertyWrapper.initializeNow()
#expect(true == _functionalLazyInitWithPropertyWrapper.isInitialized)
#expect("lazy E" == functionalLazyInitWithPropertyWrapper)
#expect(true == _functionalLazyInitWithPropertyWrapper.isInitialized)
#expect("lazy E" == functionalLazyInitWithPropertyWrapper)
#expect(true == _functionalLazyInitWithPropertyWrapper.isInitialized)

functionalLazyInitWithPropertyWrapper = "Manual E"

#expect(true == _functionalLazyInitWithPropertyWrapper.isInitialized)
#expect("Manual E" == functionalLazyInitWithPropertyWrapper)
#expect(true == _functionalLazyInitWithPropertyWrapper.isInitialized)
#expect("Manual E" == functionalLazyInitWithPropertyWrapper)
#expect(true == _functionalLazyInitWithPropertyWrapper.isInitialized)
#expect("Manual E" == functionalLazyInitWithPropertyWrapper)
#expect(true == _functionalLazyInitWithPropertyWrapper.isInitialized)
}


@Test
mutating func initializeNow_FunctionalLazy_traditional() {
#expect(false == functionalLazyInitTraditionally.isInitialized)
functionalLazyInitTraditionally.initializeNow()
#expect(true == functionalLazyInitTraditionally.isInitialized)
#expect("lazy F" == functionalLazyInitTraditionally.wrappedValue)
#expect(true == functionalLazyInitTraditionally.isInitialized)
#expect("lazy F" == functionalLazyInitTraditionally.wrappedValue)
#expect(true == functionalLazyInitTraditionally.isInitialized)

functionalLazyInitTraditionally.wrappedValue = "Manual F"

#expect(true == functionalLazyInitTraditionally.isInitialized)
#expect("Manual F" == functionalLazyInitTraditionally.wrappedValue)
#expect(true == functionalLazyInitTraditionally.isInitialized)
#expect("Manual F" == functionalLazyInitTraditionally.wrappedValue)
#expect(true == functionalLazyInitTraditionally.isInitialized)
#expect("Manual F" == functionalLazyInitTraditionally.wrappedValue)
#expect(true == functionalLazyInitTraditionally.isInitialized)
}
}

0 comments on commit 3ffb734

Please sign in to comment.