 }
 
 /// Protocol that types that can be used in an unboxing process must conform to
-public protocol UnboxCompatibleType {}
+public protocol UnboxCompatibleType {
+    /// Unbox a value, or either throw or return nil if unboxing couldn't be performed
+    static func unbox(value: Any) throws -> Self?
+}
 
 /// Protocol used to enable a raw type for Unboxing. See default implementations further down.
 public protocol UnboxableRawType: UnboxCompatibleType {

public protocol UnboxableEnum: RawRepresentable, UnboxCompatibleType {}

/// Protocol used to enable any type to be transformed from a JSON key into a dictionary key
public protocol UnboxableKey: Hashable, UnboxCompatibleType {
    /// Transform an unboxed key into a key that will be used in an unboxed dictionary
    static func transform(unboxedKey: String) -> Self?
}

    /// Unbox a required Array of values that can be transformed into its final form
    public func unbox<T: UnboxableByTransform>(key: String, isKeyPath: Bool = true, allowInvalidElements: Bool = false) throws -> [T] {
        let transform = T.makeArrayTransformClosure(allowInvalidElements: allowInvalidElements)
        return try UnboxValueResolver<[Any]>(self).resolveRequiredValueForKey(key: key, isKeyPath: isKeyPath, transform: transform)
    }

    /// Unbox an optional Array of values that can be transformed into its final form
    public func unbox<T: UnboxableByTransform>(key: String, isKeyPath: Bool = true, allowInvalidElements: Bool = false) -> [T]? {
        let transform = T.makeArrayTransformClosure(allowInvalidElements: allowInvalidElements)
        return UnboxValueResolver<[Any]>(self).resolveOptionalValueForKey(key: key, isKeyPath: isKeyPath, transform: transform)
    }
    
    /// Unbox a required raw value from a certain index in a nested Array
