-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #4 from ataibarkai/2.0Release/protocolRenaming
2.0 release/protocol renaming
- Loading branch information
Showing
20 changed files
with
475 additions
and
351 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
87 changes: 49 additions & 38 deletions
87
Sources/SemanticType/CoreStructures/SemanticTypeSpec.swift
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,112 +1,123 @@ | ||
/// A specification object statically determining the properties of a `SemanticType` object | ||
/// associated with it. | ||
public protocol GeneralizedSemanticTypeSpec { | ||
public protocol MetaValidatedSemanticTypeSpec { | ||
|
||
/// The type of the primitive value wrapped by the `SemanticType`. | ||
/// Must possess value semantics. | ||
/// | ||
/// The backing primitive must possess *value semantics* to insure that the structure of a value is | ||
/// `RawValue` must possess *value semantics* to insure that the structure of a value is | ||
/// not modified by outside forces after passing through the `SemanticType`'s `gateway` function | ||
/// and becoming stored inside of a `SemanticType` instance. | ||
associatedtype BackingPrimitiveWithValueSemantics | ||
associatedtype RawValue | ||
|
||
/// The type of the gateway-associated metadata available on the `SemanticType`. | ||
/// Must possess value semantics. | ||
/// | ||
/// The metadata must possess *value semantics* to ensure that the structure of a value is | ||
/// not modified by outside forces after passing through the `SemanticType`'s `gateway` function | ||
/// and becoming stored inside of a `SemanticType` instance. | ||
/// | ||
/// --- | ||
/// | ||
/// The metadata value is stored on the `SemanticType` instance and is publically available for access. | ||
/// It may be used to encode a compiler-accessible fascet of the sub-structure of the wrapped value | ||
/// which was veriried by the `gatewayMap` function. | ||
/// The `gatewayMap` function may verify that the internal sub-structure of a returned `RawValue` | ||
/// satisfies any number of constraints. | ||
/// `Metadata` encodes a **compiler-visible fascet** of said verified sub-structure. | ||
/// | ||
/// --- | ||
/// | ||
/// As an example: suppose we create a `NonEmptyArray` `SemanticType`, i.e. | ||
/// a type whose instances wrap an `Array` -- but which could only be created when said `Array` is non-empty. | ||
/// a type whose instances wrap an `Array` which is *always* non-empty. | ||
/// | ||
/// Unlike instances of `Array`, instances of `NonEmptyArray` are **guarenteed** to have `first` and `last` elements. | ||
/// Thus we may expose `first: Element` and `last: Element` in place of `Array`'s corresponding *optional* properties. | ||
/// | ||
/// Since we know that instances of `NonEmptyArray` are not empty, we _could_ implement said non-optionoal | ||
/// `first` and `last` overrides by forwarding the call to `Array`'s optional properties and force-unwrapping the result. | ||
/// | ||
/// While *we* know this process ought to work, the *compiler* does not -- hence the need for the force-unwrapping. | ||
/// And so we lose the celebrated compiler verification normally characterizing idiomatic swift code. | ||
/// | ||
/// Instead, we could implement `first` and `last` without circumventing compiler verifications by storing the `Array`'s `first` and `last` | ||
/// values as *metadata* during the `gatewayMap`ing (where we could return an error if `first` and `last` are not available). | ||
/// Then the non-optional `first` and `last` properties could be implemented by querying said metadata values. | ||
associatedtype GatewayMetadataWithValueSemantics | ||
/// The non-optional `first` and `last` properties on `NonEmptyArray` could then be implemented by querying said metadata values. | ||
associatedtype Metadata | ||
|
||
/// The type of the error which could be returned when attempting to create instance of the `SemanticType`. | ||
associatedtype Error: Swift.Error | ||
|
||
/// The output of the [gatewayMap function](x-source-tag://SemanticTypeSpec.gateway). | ||
/// See additional documentation on the [struct definition](x-source-tag://GeneralizedSemanticTypeSpec_GatewayOutput) | ||
/// See additional documentation on the [struct definition](x-source-tag://MetaValidatedSemanticTypeSpec_GatewayOutput) | ||
/// | ||
/// - Tag: GeneralizedSemanticTypeSpec.GatewayOutput | ||
typealias GatewayOutput = GeneralizedSemanticTypeSpec_GatewayOutput<BackingPrimitiveWithValueSemantics, GatewayMetadataWithValueSemantics> | ||
/// - Tag: MetaValidatedSemanticTypeSpec.GatewayOutput | ||
typealias GatewayOutput = MetaValidatedSemanticTypeSpec_GatewayOutput<RawValue, Metadata> | ||
|
||
/// A function gating the creation of all `SemanticType` instances associated with this Spec. | ||
/// | ||
/// - Parameter preMap: The primitive value to be analyzed and modified for association with a `SemanticType` instance. | ||
/// - Returns: If a `SemanticType` instance should be created given the provided input, returns the backing primitive | ||
/// - Parameter preMap: The `RawValue` to be analyzed and modified for association with a `SemanticType` instance. | ||
/// - Returns: If a `SemanticType` instance should be created given the provided input, returns the (possibly transformed) `RawValue` to back the created `SemanticType` instance. Otherwise, returns the error specifying why the instance cannot be creted given the provided input. | ||
/// - Tag: SemanticTypeSpec.gateway | ||
static func gateway( | ||
preMap: BackingPrimitiveWithValueSemantics | ||
preMap: RawValue | ||
) -> Result<GatewayOutput, Error> | ||
} | ||
/// The output of the [gatewayMap function](x-source-tag://SemanticTypeSpec.gateway). | ||
/// | ||
/// | ||
/// NOTE: Since Swift does not currently support nesting definitions of types nested inside a protocol, | ||
/// we utilize a naming convention + [a typealias on the target protocol](x-source-tag://GeneralizedSemanticTypeSpec.GatewayOutput) | ||
/// we utilize a naming convention + [a typealias on the target protocol](x-source-tag://MetaValidatedSemanticTypeSpec.GatewayOutput) | ||
/// to effectively achieve this goal. | ||
/// In other words, this type should be viewed as if it were nested under the `GeneralizedSemanticTypeSpec` protocol. | ||
/// In other words, this type should be viewed as if it were nested under the `MetaValidatedSemanticTypeSpec` protocol. | ||
/// | ||
/// - Tag: GeneralizedSemanticTypeSpec_GatewayOutput | ||
public struct GeneralizedSemanticTypeSpec_GatewayOutput<BackingPrimitiveWithValueSemantics, GatewayMetadataWithValueSemantics> { | ||
/// - Tag: MetaValidatedSemanticTypeSpec_GatewayOutput | ||
public struct MetaValidatedSemanticTypeSpec_GatewayOutput<RawValue, Metadata> { | ||
|
||
/// The primitive value to back a succesfully-created `SemanticType` instance. | ||
/// The behavior of the `SemanticType` manifestation largely revolves around this type | ||
/// The behavior of the `SemanticType` construct largely revolves around this field. | ||
/// (see [SemanticType](x-source-tag://SemanticType)). | ||
var backingPrimitvie: BackingPrimitiveWithValueSemantics | ||
var rawValue: RawValue | ||
|
||
/// Additinoal metadata object available to the successfully-created `SemanticType` instance. | ||
/// Additinoal metadata available to the successfully-created `SemanticType` instance. | ||
/// May be utilized to provide compiler-verified extensions on the SemanticType, taking advantage of the | ||
/// constraints satisfied by the distilled primitive. | ||
var metadata: GatewayMetadataWithValueSemantics | ||
/// constraints satisfied by the distilled `RawValue`. | ||
var metadata: Metadata | ||
} | ||
|
||
|
||
/// A `SemanticTypeSpec` with no gateway metadata. | ||
public protocol SemanticTypeSpec: GeneralizedSemanticTypeSpec where GatewayMetadataWithValueSemantics == () { | ||
public protocol ValidatedSemanticTypeSpec: MetaValidatedSemanticTypeSpec where Metadata == () { | ||
static func gateway( | ||
preMap: BackingPrimitiveWithValueSemantics | ||
) -> Result<BackingPrimitiveWithValueSemantics, Error> | ||
preMap: RawValue | ||
) -> Result<RawValue, Error> | ||
} | ||
extension SemanticTypeSpec { | ||
extension ValidatedSemanticTypeSpec { | ||
// Implement the parent protocol's requirements in terms of `Self's` requirements: | ||
public static func gateway( | ||
preMap: BackingPrimitiveWithValueSemantics | ||
preMap: RawValue | ||
) -> Result<GatewayOutput, Error> { | ||
return gateway(preMap: preMap) | ||
.map { .init(backingPrimitvie: $0, metadata: ()) } | ||
.map { .init(rawValue: $0, metadata: ()) } | ||
} | ||
} | ||
|
||
/// A `SemanticTypeSpec` whose `gateway` function never errors. | ||
public protocol ErrorlessSemanticTypeSpec: SemanticTypeSpec where Error == Never { | ||
public protocol ErrorlessSemanticTypeSpec: ValidatedSemanticTypeSpec where Error == Never { | ||
static func gateway( | ||
preMap: BackingPrimitiveWithValueSemantics | ||
) -> BackingPrimitiveWithValueSemantics | ||
preMap: RawValue | ||
) -> RawValue | ||
} | ||
extension ErrorlessSemanticTypeSpec { | ||
// Implement the parent protocol's requirements in terms of `Self's` requirements: | ||
public static func gateway( | ||
preMap: BackingPrimitiveWithValueSemantics | ||
) -> Result<BackingPrimitiveWithValueSemantics, Error> { | ||
preMap: RawValue | ||
) -> Result<RawValue, Error> { | ||
return .success(gateway(preMap: preMap)) | ||
} | ||
|
||
// By default, `ErrorlessSemanticTypeSpec` uses the identity function as a gateway | ||
// (i.e. no transformation is performed on `RawValue`). | ||
public static func gateway( | ||
preMap: BackingPrimitiveWithValueSemantics | ||
) -> BackingPrimitiveWithValueSemantics { | ||
preMap: RawValue | ||
) -> RawValue { | ||
return preMap | ||
} | ||
} | ||
|
38 changes: 19 additions & 19 deletions
38
...e_ConditionalExtensions/DoublyConditionalConformances/ErrorlessSemanticType_Numeric.swift
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,50 +1,50 @@ | ||
/// A marker protocol to be conformed to by a `SemanticTypeSpec` type | ||
/// to conditionally provide `Numeric` support for its associated `SemanticType`. | ||
/// | ||
/// A marker protocol. | ||
/// If a `SemanticTypeSpec` conforms to this protocol, its associated `SemanticType` | ||
/// will conform to `Numeric`. | ||
public protocol ShouldBeNumeric: GeneralizedSemanticTypeSpec | ||
/// | ||
/// `Numeric` support may not make sense for all | ||
/// `SemanticType`s associated with a `Numeric` `RawValue` | ||
/// (for instance, [`Second` * `Second` = `Second`] does not make semantic sense). | ||
/// Nevertheless, we *can* provide an implementation in all such cases. | ||
/// | ||
/// We allow the `Spec` backing the `SemanticType` to signal whether `Numeric` | ||
/// support should be provided by conforming to the `ShouldBeNumeric` marker protocol. | ||
public protocol ShouldBeNumeric: MetaValidatedSemanticTypeSpec | ||
where | ||
BackingPrimitiveWithValueSemantics: Numeric { } | ||
RawValue: Numeric { } | ||
|
||
extension SemanticType: Numeric | ||
where | ||
Spec: ShouldBeNumeric, // `Numeric` support may not make sense for all | ||
// `SemanticType`s associated with a `Numeric` `BackingPrimitiveWithValueSemantics` | ||
// (for instance, [`Second` * `Second` = `Second`] does not make semantic sense). | ||
// Nevertheless, we *can* provide an implementation in all such cases. | ||
// | ||
// We allow the `Spec` backing the `SemanticType` to signal whether `Numeric` | ||
// support should be provided by conforming to the `ShouldBeNumeric` marker protocol. | ||
Spec: ShouldBeNumeric, | ||
Spec.Error == Never | ||
{ | ||
public typealias Magnitude = Spec.BackingPrimitiveWithValueSemantics.Magnitude | ||
public typealias Magnitude = Spec.RawValue.Magnitude | ||
|
||
public init?<T>(exactly source: T) where T : BinaryInteger { | ||
guard let inside = Spec.BackingPrimitiveWithValueSemantics.init(exactly: source) | ||
guard let inside = Spec.RawValue.init(exactly: source) | ||
else { return nil } | ||
|
||
self.init(inside) | ||
} | ||
|
||
public var magnitude: Spec.BackingPrimitiveWithValueSemantics.Magnitude { | ||
backingPrimitive.magnitude | ||
public var magnitude: Spec.RawValue.Magnitude { | ||
rawValue.magnitude | ||
} | ||
|
||
public static func * (lhs: Self, rhs: Self) -> Self { | ||
Self(lhs.backingPrimitive * rhs.backingPrimitive) | ||
Self(lhs.rawValue * rhs.rawValue) | ||
} | ||
|
||
public static func *= (lhs: inout Self, rhs: Self) { | ||
lhs.backingPrimitive *= rhs.backingPrimitive | ||
lhs.rawValue *= rhs.rawValue | ||
} | ||
} | ||
|
||
|
||
extension SemanticType: SignedNumeric | ||
where | ||
Spec: ShouldBeNumeric, | ||
Spec.BackingPrimitiveWithValueSemantics: SignedNumeric, | ||
Spec.RawValue: SignedNumeric, | ||
Spec.Error == Never | ||
{ } | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.