From 9b618d55fa23900575cd7f82feab0e36f945a01a Mon Sep 17 00:00:00 2001 From: Michael Housh Date: Thu, 29 Jan 2026 20:50:33 -0500 Subject: [PATCH] WIP: Adds more tagged types for rectangular size calculations. --- .../DatabaseClient/Internal/TrunkSizes.swift | 6 +-- Sources/ManualDClient/Interface.swift | 50 +++++++++++++------ Sources/ManualDClient/Live.swift | 9 ++-- Sources/ManualDCore/TaggedTypes.swift | 17 +++++-- Sources/ManualDCore/TrunkSize.swift | 12 ++--- .../ManualDClient+calculateDuctSizes.swift | 12 +++-- .../Extensions/TrunkSizeForm+extensions.swift | 4 +- .../Views/DuctSizing/TrunkSizeForm.swift | 2 +- .../ManualDClientTests.swift | 2 +- 9 files changed, 75 insertions(+), 39 deletions(-) diff --git a/Sources/DatabaseClient/Internal/TrunkSizes.swift b/Sources/DatabaseClient/Internal/TrunkSizes.swift index c764d73..1ea7d03 100644 --- a/Sources/DatabaseClient/Internal/TrunkSizes.swift +++ b/Sources/DatabaseClient/Internal/TrunkSizes.swift @@ -103,7 +103,7 @@ extension TrunkSize.Create { .init( projectID: projectID, type: type, - height: height, + height: height?.rawValue, name: name ) } @@ -270,7 +270,7 @@ final class TrunkModel: Model, @unchecked Sendable { projectID: $project.id, type: .init(rawValue: type)!, rooms: rooms, - height: height, + height: height.map { .init(rawValue: $0) }, name: name ) @@ -283,7 +283,7 @@ final class TrunkModel: Model, @unchecked Sendable { if let type = updates.type, type.rawValue != self.type { self.type = type.rawValue } - if let height = updates.height, height != self.height { + if let height = updates.height?.rawValue, height != self.height { self.height = height } if let name = updates.name, name != self.name { diff --git a/Sources/ManualDClient/Interface.swift b/Sources/ManualDClient/Interface.swift index 60aa216..370dc80 100644 --- a/Sources/ManualDClient/Interface.swift +++ b/Sources/ManualDClient/Interface.swift @@ -18,8 +18,7 @@ extension DependencyValues { public struct ManualDClient: Sendable { public var ductSize: @Sendable (CFM, DesignFrictionRate) async throws -> DuctSizeResponse public var frictionRate: @Sendable (FrictionRateRequest) async throws -> FrictionRate - public var rectangularSize: - @Sendable (RectangularSizeRequest) async throws -> RectangularSizeResponse + public var rectangularSize: @Sendable (RoundSize, Height) async throws -> RectangularSizeResponse public func ductSize( cfm designCFM: Int, @@ -34,6 +33,21 @@ public struct ManualDClient: Sendable { ) async throws -> DuctSizeResponse { try await ductSize(.init(rawValue: Int(designCFM)), .init(rawValue: designFrictionRate)) } + + public func rectangularSize( + round roundSize: RoundSize, + height: Height + ) async throws -> RectangularSizeResponse { + try await rectangularSize(roundSize, height) + } + + public func rectangularSize( + round roundSize: Int, + height: Int + ) async throws -> RectangularSizeResponse { + try await rectangularSize(.init(rawValue: roundSize), .init(rawValue: height)) + } + } extension ManualDClient: TestDependencyKey { @@ -90,23 +104,31 @@ extension ManualDClient { } } - public struct RectangularSizeRequest: Codable, Equatable, Sendable { - public let roundSize: Int - public let height: Int - - public init(round roundSize: Int, height: Int) { - self.roundSize = roundSize - self.height = height - } - } + // public struct RectangularSizeRequest: Codable, Equatable, Sendable { + // public let roundSize: RoundSize + // public let height: Height + // + // public init(round roundSize: RoundSize, height: Height) { + // self.roundSize = roundSize + // self.height = height + // } + // + // public init(round roundSize: Int, height: Int) { + // self.init(round: .init(rawValue: roundSize), height: .init(rawValue: height)) + // } + // } public struct RectangularSizeResponse: Codable, Equatable, Sendable { - public let height: Int - public let width: Int + public let height: Height + public let width: Width - public init(height: Int, width: Int) { + public init(height: Height, width: Width) { self.height = height self.width = width } + + public init(height: Int, width: Int) { + self.init(height: .init(rawValue: height), width: .init(rawValue: width)) + } } } diff --git a/Sources/ManualDClient/Live.swift b/Sources/ManualDClient/Live.swift index 3ee2193..56f2eaa 100644 --- a/Sources/ManualDClient/Live.swift +++ b/Sources/ManualDClient/Live.swift @@ -39,9 +39,12 @@ extension ManualDClient: DependencyKey { // let groupLengths = request.effectiveLengthGroups.totalEffectiveLength // return trunkLengths + runoutLengths + groupLengths // }, - rectangularSize: { request in - let width = (Double.pi * (pow(Double(request.roundSize) / 2.0, 2.0))) / Double(request.height) - return .init(height: request.height, width: Int(width.rounded(.toNearestOrEven))) + rectangularSize: { round, height in + let width = (Double.pi * (pow(Double(round.rawValue) / 2.0, 2.0))) / Double(height.rawValue) + return .init( + height: height, + width: .init(rawValue: Int(width.rounded(.toNearestOrEven))) + ) } ) } diff --git a/Sources/ManualDCore/TaggedTypes.swift b/Sources/ManualDCore/TaggedTypes.swift index 4b2a84f..9ae8c07 100644 --- a/Sources/ManualDCore/TaggedTypes.swift +++ b/Sources/ManualDCore/TaggedTypes.swift @@ -1,7 +1,16 @@ import Tagged -public enum CFMTag {} -public typealias CFM = Tagged +/// A name space for general tag types. +public enum Tag { + public enum CFM {} + public enum DesignFrictionRate {} + public enum Height {} + public enum Round {} + public enum Width {} +} -public enum DesignFrictionRateTag {} -public typealias DesignFrictionRate = Tagged +public typealias CFM = Tagged +public typealias DesignFrictionRate = Tagged +public typealias Height = Tagged +public typealias RoundSize = Tagged +public typealias Width = Tagged diff --git a/Sources/ManualDCore/TrunkSize.swift b/Sources/ManualDCore/TrunkSize.swift index dc16d70..ad0483c 100644 --- a/Sources/ManualDCore/TrunkSize.swift +++ b/Sources/ManualDCore/TrunkSize.swift @@ -16,7 +16,7 @@ public struct TrunkSize: Codable, Equatable, Identifiable, Sendable { public let rooms: [RoomProxy] /// An optional rectangular height used to calculate the equivalent /// rectangular size of the trunk. - public let height: Int? + public let height: Height? /// An optional name / label used for identifying the trunk. public let name: String? @@ -25,7 +25,7 @@ public struct TrunkSize: Codable, Equatable, Identifiable, Sendable { projectID: Project.ID, type: TrunkType, rooms: [RoomProxy], - height: Int? = nil, + height: Height? = nil, name: String? = nil ) { self.id = id @@ -49,7 +49,7 @@ extension TrunkSize { public let rooms: [Room.ID: [Int]] /// An optional rectangular height used to calculate the equivalent /// rectangular size of the trunk. - public let height: Int? + public let height: Height? /// An optional name / label used for identifying the trunk. public let name: String? @@ -57,7 +57,7 @@ extension TrunkSize { projectID: Project.ID, type: TrunkType, rooms: [Room.ID: [Int]], - height: Int? = nil, + height: Height? = nil, name: String? = nil ) { self.projectID = projectID @@ -79,14 +79,14 @@ extension TrunkSize { public let rooms: [Room.ID: [Int]]? /// An optional rectangular height used to calculate the equivalent /// rectangular size of the trunk. - public let height: Int? + public let height: Height? /// An optional name / label used for identifying the trunk. public let name: String? public init( type: TrunkType? = nil, rooms: [Room.ID: [Int]]? = nil, - height: Int? = nil, + height: Height? = nil, name: String? = nil ) { self.type = type diff --git a/Sources/ProjectClient/Internal/ManualDClient+calculateDuctSizes.swift b/Sources/ProjectClient/Internal/ManualDClient+calculateDuctSizes.swift index d66a71c..8a0ae2f 100644 --- a/Sources/ProjectClient/Internal/ManualDClient+calculateDuctSizes.swift +++ b/Sources/ProjectClient/Internal/ManualDClient+calculateDuctSizes.swift @@ -64,9 +64,10 @@ extension ManualDClient { if let rectangularSize { let response = try await self.rectangularSize( - .init(round: sizes.finalSize, height: rectangularSize.height) + round: sizes.finalSize, + height: rectangularSize.height ) - rectangularWidth = response.width + rectangularWidth = response.width.rawValue } retval.append( @@ -118,9 +119,10 @@ extension ManualDClient { var width: Int? = nil if let height = trunk.height { let rectangularSize = try await self.rectangularSize( - .init(round: sizes.finalSize, height: height) + round: .init(rawValue: sizes.finalSize), + height: height ) - width = rectangularSize.width + width = rectangularSize.width.rawValue } retval.append( @@ -129,7 +131,7 @@ extension ManualDClient { ductSize: .init( designCFM: designCFM, sizes: sizes, - height: trunk.height, + height: trunk.height?.rawValue, width: width ) ) diff --git a/Sources/ViewController/Extensions/TrunkSizeForm+extensions.swift b/Sources/ViewController/Extensions/TrunkSizeForm+extensions.swift index b1057c2..f18fac1 100644 --- a/Sources/ViewController/Extensions/TrunkSizeForm+extensions.swift +++ b/Sources/ViewController/Extensions/TrunkSizeForm+extensions.swift @@ -9,7 +9,7 @@ extension SiteRoute.View.ProjectRoute.DuctSizingRoute.TrunkSizeForm { projectID: projectID, type: type, rooms: makeRooms(logger: logger), - height: height, + height: height.map { .init(rawValue: $0) }, name: name ) } @@ -18,7 +18,7 @@ extension SiteRoute.View.ProjectRoute.DuctSizingRoute.TrunkSizeForm { try .init( type: type, rooms: makeRooms(logger: logger), - height: height, + height: height.map { .init(rawValue: $0) }, name: name ) } diff --git a/Sources/ViewController/Views/DuctSizing/TrunkSizeForm.swift b/Sources/ViewController/Views/DuctSizing/TrunkSizeForm.swift index 8f281ef..fc2a00e 100644 --- a/Sources/ViewController/Views/DuctSizing/TrunkSizeForm.swift +++ b/Sources/ViewController/Views/DuctSizing/TrunkSizeForm.swift @@ -67,7 +67,7 @@ struct TrunkSizeForm: HTML, Sendable { "Height", .type(.text), .name("height"), - .value(trunk?.height), + .value(trunk?.height?.rawValue), .placeholder("8 (Optional)"), ) } diff --git a/Tests/ManualDClientTests/ManualDClientTests.swift b/Tests/ManualDClientTests/ManualDClientTests.swift index 9730792..a159135 100644 --- a/Tests/ManualDClientTests/ManualDClientTests.swift +++ b/Tests/ManualDClientTests/ManualDClientTests.swift @@ -33,7 +33,7 @@ struct ManualDClientTests { @Test func equivalentRectangularDuct() async throws { - let response = try await manualD.rectangularSize(.init(round: 7, height: 8)) + let response = try await manualD.rectangularSize(round: 7, height: 8) #expect(response.height == 8) #expect(response.width == 5) }