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 26, 2024
1 parent 60e6ed8 commit b1ecf0f
Show file tree
Hide file tree
Showing 13 changed files with 232 additions and 12 deletions.
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 b1ecf0f

Please sign in to comment.