@@ -99,8 +99,11 @@ public class ConfidenceFeatureProvider: FeatureProvider {
9999 public func getObjectEvaluation( key: String , defaultValue: OpenFeature . Value , context: EvaluationContext ? )
100100 throws -> OpenFeature . ProviderEvaluation < OpenFeature . Value >
101101 {
102- // Convert Struct Value to
103- try confidence. getEvaluation ( key: key, defaultValue: defaultValue) . toProviderEvaluation ( )
102+ guard let nativeDefault = defaultValue. asNativeDictionary ( ) else {
103+ throw OpenFeatureError . generalError ( message: " Unexpected error handling the default value " )
104+ }
105+ let evaluation = confidence. getEvaluation ( key: key, defaultValue: nativeDefault)
106+ return try evaluation. toProviderEvaluationWithValueConversion ( )
104107 }
105108
106109 public func observe( ) -> AnyPublisher < OpenFeature . ProviderEvent ? , Never > {
@@ -118,7 +121,8 @@ public class ConfidenceFeatureProvider: FeatureProvider {
118121}
119122
120123extension Evaluation {
121- func toProviderEvaluation( ) throws -> ProviderEvaluation < T > {
124+ /// Throws an OpenFeature error if this evaluation contains an error code
125+ private func throwIfError( ) throws {
122126 if let errorCode = self . errorCode {
123127 switch errorCode {
124128 case . providerNotReady:
@@ -137,12 +141,152 @@ extension Evaluation {
137141 throw OpenFeatureError . generalError ( message: message)
138142 }
139143 }
144+ }
145+
146+ func toProviderEvaluation( ) throws -> ProviderEvaluation < T > {
147+ try throwIfError ( )
140148 return ProviderEvaluation (
141149 value: self . value,
142150 variant: self . variant,
143- reason: self . reason. rawValue,
151+ reason: Reason . targetingMatch. rawValue, // TODO VERIFY THIS!
152+ errorCode: nil ,
153+ errorMessage: nil
154+ )
155+ }
156+ }
157+
158+ extension Evaluation where T == [ String : Any ] {
159+ func toProviderEvaluationWithValueConversion( ) throws -> ProviderEvaluation < OpenFeature . Value > {
160+ try throwIfError ( )
161+ let openFeatureValue = OpenFeature . Value. fromNativeDictionary ( self . value)
162+ return ProviderEvaluation (
163+ value: openFeatureValue,
164+ variant: self . variant,
165+ reason: Reason . targetingMatch. rawValue, // TODO VERIFY THIS!
144166 errorCode: nil ,
145167 errorMessage: nil
146168 )
147169 }
148170}
171+
172+ extension OpenFeature . Value {
173+ /// Converts an OpenFeature Value to a Dictionary of native Swift types.
174+ ///
175+ /// - Returns: A dictionary where keys are Strings and values are native Swift types:
176+ /// - Bool for boolean values
177+ /// - String for string values
178+ /// - Int64 for integer values
179+ /// - Double for double values
180+ /// - Date for date values
181+ /// - [Any] for list values (recursively converted)
182+ /// - [String: Any] for nested structure values (recursively converted)
183+ /// - NSNull for null values
184+ /// - Returns: nil if the Value is not a structure type
185+ public func asNativeDictionary( ) -> [ String : Any ] ? {
186+ guard case let . structure( valueMap) = self else {
187+ return nil
188+ }
189+
190+ return valueMap. mapValues { value in
191+ return value. asNativeType ( )
192+ }
193+ }
194+
195+ /// Converts an OpenFeature Value to its corresponding native Swift type.
196+ ///
197+ /// - Returns: The native Swift representation:
198+ /// - Bool for boolean values
199+ /// - String for string values
200+ /// - Int64 for integer values
201+ /// - Double for double values
202+ /// - Date for date values
203+ /// - [Any] for list values (recursively converted)
204+ /// - [String: Any] for structure values (recursively converted)
205+ /// - NSNull for null values
206+ public func asNativeType( ) -> Any {
207+ switch self {
208+ case . boolean( let value) :
209+ return value
210+ case . string( let value) :
211+ return value
212+ case . integer( let value) :
213+ return value
214+ case . double( let value) :
215+ return value
216+ case . date( let value) :
217+ return value
218+ case . list( let values) :
219+ return values. map { $0. asNativeType ( ) }
220+ case . structure( let valueMap) :
221+ return valueMap. mapValues { $0. asNativeType ( ) }
222+ case . null:
223+ return NSNull ( )
224+ }
225+ }
226+
227+ /// Creates an OpenFeature Value from a native Swift dictionary.
228+ ///
229+ /// - Parameter dictionary: A dictionary with String keys and Any values
230+ /// - Returns: An OpenFeature Value structure containing the converted dictionary
231+ public static func fromNativeDictionary( _ dictionary: [ String : Any ] ) -> OpenFeature . Value {
232+ let convertedMap = dictionary. mapValues { value in
233+ return fromNativeType ( value)
234+ }
235+ return . structure( convertedMap)
236+ }
237+
238+ /// Creates an OpenFeature Value from a native Swift type.
239+ ///
240+ /// - Parameter value: The native Swift value to convert
241+ /// - Returns: The corresponding OpenFeature Value
242+ public static func fromNativeType( _ value: Any ) -> OpenFeature . Value {
243+ // Handle numeric types first
244+ if let boolValue = value as? Bool {
245+ return . boolean( boolValue)
246+ }
247+ if let stringValue = value as? String {
248+ return . string( stringValue)
249+ }
250+
251+ // Handle integer types
252+ if let intValue = value as? Int {
253+ return . integer( Int64 ( intValue) )
254+ }
255+ if let int64Value = value as? Int64 {
256+ return . integer( int64Value)
257+ }
258+ if let int32Value = value as? Int32 {
259+ return . integer( Int64 ( int32Value) )
260+ }
261+
262+ // Handle floating point types
263+ if let doubleValue = value as? Double {
264+ return . double( doubleValue)
265+ }
266+ if let floatValue = value as? Float {
267+ return . double( Double ( floatValue) )
268+ }
269+
270+ // Handle other types
271+ return handleOtherNativeTypes ( value)
272+ }
273+
274+ private static func handleOtherNativeTypes( _ value: Any ) -> OpenFeature . Value {
275+ if let dateValue = value as? Date {
276+ return . date( dateValue)
277+ }
278+ if let arrayValue = value as? [ Any ] {
279+ let convertedArray = arrayValue. map { fromNativeType ( $0) }
280+ return . list( convertedArray)
281+ }
282+ if let dictValue = value as? [ String : Any ] {
283+ let convertedDict = dictValue. mapValues { fromNativeType ( $0) }
284+ return . structure( convertedDict)
285+ }
286+ if value is NSNull {
287+ return . null
288+ }
289+ // For unknown types, convert to string representation
290+ return . string( String ( describing: value) )
291+ }
292+ }
0 commit comments