1
- import Tricks: static_fieldnames, static_fieldtypes
1
+ using Tricks: static_fieldnames
2
2
3
3
const DEFAULT_DIM_BASE_TYPE = FixedRational{DEFAULT_NUMERATOR_TYPE,DEFAULT_DENOM}
4
4
const DEFAULT_VALUE_TYPE = Float64
@@ -17,7 +17,7 @@ the need to define many other functions.
17
17
The key function that one could wish to overload is
18
18
`DynamicQuantities.dimension_name(::AbstractDimensions, k::Symbol)` for mapping from a field name
19
19
to a base unit (e.g., `length` by default maps to `m`). You may also need to overload
20
- `DynamicQuantities.constructor_of (::Type{T})` in case of non-standard construction.
20
+ `constructorof (::Type{T})` in case of non-standard construction.
21
21
"""
22
22
abstract type AbstractDimensions{R} end
23
23
@@ -103,13 +103,13 @@ struct Dimensions{R<:Real} <: AbstractDimensions{R}
103
103
amount:: R
104
104
end
105
105
106
- (:: Type{D} )(:: Type{R} ; kws... ) where {R,D<: AbstractDimensions } = constructor_of (D){R} ((tryrationalize (R, get (kws, k, zero (R))) for k in static_fieldnames (D)). .. )
107
- (:: Type{D} )(; kws... ) where {R,D<: AbstractDimensions{R} } = constructor_of (D)(R; kws... )
106
+ (:: Type{D} )(:: Type{R} ; kws... ) where {R,D<: AbstractDimensions } = with_type_parameters (D, R) ((tryrationalize (R, get (kws, k, zero (R))) for k in dimension_names (D)). .. )
107
+ (:: Type{D} )(; kws... ) where {R,D<: AbstractDimensions{R} } = constructorof (D)(R; kws... )
108
108
(:: Type{D} )(; kws... ) where {D<: AbstractDimensions } = D (DEFAULT_DIM_BASE_TYPE; kws... )
109
109
function (:: Type{D} )(d:: D2 ) where {R,D<: AbstractDimensions{R} ,D2<: AbstractDimensions }
110
- fieldnames_equal (D, D2) ||
110
+ dimension_names_equal (D, D2) ||
111
111
error (" Cannot create a dimensions of `$(D) ` from `$(D2) `. Please write a custom method for construction." )
112
- D ((getproperty (d, k) for k in static_fieldnames (D)). .. )
112
+ D ((getproperty (d, k) for k in dimension_names (D)). .. )
113
113
end
114
114
115
115
const DEFAULT_DIM_TYPE = Dimensions{DEFAULT_DIM_BASE_TYPE}
@@ -175,28 +175,79 @@ const ABSTRACT_QUANTITY_TYPES = ((AbstractQuantity, Number, Quantity), (Abstract
175
175
176
176
for (type, base_type, _) in ABSTRACT_QUANTITY_TYPES
177
177
@eval begin
178
- (:: Type{Q} )(x:: T , :: Type{D} ; kws... ) where {D<: AbstractDimensions ,T<: $base_type ,T2,Q<: $type{T2} } = constructor_of (Q)(convert (T2, x), D (; kws... ))
179
- (:: Type{Q} )(x:: $base_type , :: Type{D} ; kws... ) where {D<: AbstractDimensions ,Q<: $type } = constructor_of (Q)(x, D (; kws... ))
180
- (:: Type{Q} )(x:: T ; kws... ) where {T<: $base_type ,T2,Q<: $type{T2} } = constructor_of (Q)(convert (T2, x), dim_type (Q)(; kws... ))
181
- (:: Type{Q} )(x:: $base_type ; kws... ) where {Q<: $type } = constructor_of (Q)(x, dim_type (Q)(; kws... ))
178
+ (:: Type{Q} )(x:: T , :: Type{D} ; kws... ) where {D<: AbstractDimensions ,T<: $base_type ,T2,Q<: $type{T2} } = constructorof (Q)(convert (T2, x), D (; kws... ))
179
+ (:: Type{Q} )(x:: $base_type , :: Type{D} ; kws... ) where {D<: AbstractDimensions ,Q<: $type } = constructorof (Q)(x, D (; kws... ))
180
+ (:: Type{Q} )(x:: T ; kws... ) where {T<: $base_type ,T2,Q<: $type{T2} } = constructorof (Q)(convert (T2, x), dim_type (Q)(; kws... ))
181
+ (:: Type{Q} )(x:: $base_type ; kws... ) where {Q<: $type } = constructorof (Q)(x, dim_type (Q)(; kws... ))
182
182
end
183
183
for (type2, _, _) in ABSTRACT_QUANTITY_TYPES
184
184
@eval begin
185
- (:: Type{Q} )(q:: $type2 ) where {T,D<: AbstractDimensions ,Q<: $type{T,D} } = constructor_of (Q)(convert (T, ustrip (q)), convert (D, dimension (q)))
186
- (:: Type{Q} )(q:: $type2 ) where {T,Q<: $type{T} } = constructor_of (Q)(convert (T, ustrip (q)), dimension (q))
187
- (:: Type{Q} )(q:: $type2 ) where {Q<: $type } = constructor_of (Q)(ustrip (q), dimension (q))
185
+ (:: Type{Q} )(q:: $type2 ) where {T,D<: AbstractDimensions ,Q<: $type{T,D} } = constructorof (Q)(convert (T, ustrip (q)), convert (D, dimension (q)))
186
+ (:: Type{Q} )(q:: $type2 ) where {T,Q<: $type{T} } = constructorof (Q)(convert (T, ustrip (q)), dimension (q))
187
+ (:: Type{Q} )(q:: $type2 ) where {Q<: $type } = constructorof (Q)(ustrip (q), dimension (q))
188
188
end
189
189
end
190
190
end
191
191
192
192
const DEFAULT_QUANTITY_TYPE = Quantity{DEFAULT_VALUE_TYPE, DEFAULT_DIM_TYPE}
193
193
194
- new_dimensions (:: Type{D} , dims... ) where {D<: AbstractDimensions } = constructor_of (D)(dims... )
195
- new_quantity (:: Type{Q} , l, r) where {Q<: UnionAbstractQuantity } = constructor_of (Q)(l, r)
194
+ new_dimensions (:: Type{D} , dims... ) where {D<: AbstractDimensions } = constructorof (D)(dims... )
195
+ new_quantity (:: Type{Q} , l, r) where {Q<: UnionAbstractQuantity } = constructorof (Q)(l, r)
196
196
197
197
dim_type (:: Type{Q} ) where {T,D<: AbstractDimensions ,Q<: UnionAbstractQuantity{T,D} } = D
198
198
dim_type (:: Type{<:UnionAbstractQuantity} ) = DEFAULT_DIM_TYPE
199
- constructor_of (:: Type{T} ) where {T} = Base. typename (T). wrapper
199
+
200
+ """
201
+ constructorof(::Type{<:AbstractDimensions})
202
+ constructorof(::Type{<:UnionAbstractQuantity})
203
+
204
+ Return the constructor of the given type. This is used to create new objects
205
+ of the same type as the input. Overload a method for a new type, especially
206
+ if you need custom behavior.
207
+ """
208
+ constructorof (:: Type{<:Dimensions} ) = Dimensions
209
+ constructorof (:: Type{<:Quantity} ) = Quantity
210
+ constructorof (:: Type{<:GenericQuantity} ) = GenericQuantity
211
+
212
+ """
213
+ with_type_parameters(::Type{<:AbstractDimensions}, ::Type{R})
214
+ with_type_parameters(::Type{<:UnionAbstractQuantity}, ::Type{T}, ::Type{D})
215
+
216
+ Return the type with the given type parameters instead of the ones in the input type.
217
+ This is used to get `Dimensions{R}` from input `(Dimensions{R1}, R)`, for example.
218
+ Overload a method for a new type, especially if you need custom behavior.
219
+ """
220
+ function with_type_parameters (:: Type{<:Dimensions} , :: Type{R} ) where {R}
221
+ return Dimensions{R}
222
+ end
223
+ function with_type_parameters (:: Type{<:Quantity} , :: Type{T} , :: Type{D} ) where {T,D}
224
+ return Quantity{T,D}
225
+ end
226
+ function with_type_parameters (:: Type{<:GenericQuantity} , :: Type{T} , :: Type{D} ) where {T,D}
227
+ return GenericQuantity{T,D}
228
+ end
229
+
230
+ # The following functions should be overloaded for special types
231
+ function constructorof (:: Type{T} ) where {T<: Union{UnionAbstractQuantity,AbstractDimensions} }
232
+ return Base. typename (T). wrapper
233
+ end
234
+ function with_type_parameters (:: Type{D} , :: Type{R} ) where {D<: AbstractDimensions ,R}
235
+ return constructorof (D){R}
236
+ end
237
+ function with_type_parameters (:: Type{Q} , :: Type{T} , :: Type{D} ) where {Q<: UnionAbstractQuantity ,T,D}
238
+ return constructorof (Q){T,D}
239
+ end
240
+
241
+ """
242
+ dimension_names(::Type{<:AbstractDimensions})
243
+
244
+ Return a tuple of symbols with the names of the dimensions of the given type.
245
+ This should be static so that it can be hardcoded during compilation.
246
+ The default is to use `fieldnames`, but you can overload this for custom behavior.
247
+ """
248
+ @inline function dimension_names (:: Type{D} ) where {D<: AbstractDimensions }
249
+ return static_fieldnames (D)
250
+ end
200
251
201
252
struct DimensionError{Q1,Q2} <: Exception
202
253
q1:: Q1
0 commit comments