Merge pull request #815 from naithar/NSAffineTransform

diff --git a/Docs/Status.md b/Docs/Status.md
index d038e90..071a49c 100644
--- a/Docs/Status.md
+++ b/Docs/Status.md
@@ -226,7 +226,7 @@
     | `NSGeometry`                      | Mostly Complete | Substantial   | `NSIntegralRectWithOptions` `.AlignRectFlipped` support remains unimplemented |
     | `CGFloat`                         | Complete        | Substantial   |                                                                               |
     | `AffineTransform`                 | Complete        | None          |                                                                               |
-    | `NSAffineTransform`               | Mostly Complete | Substnatial   | `NSCoding` remains unimplemented                                              |
+    | `NSAffineTransform`               | Complete        | Substnatial   |                                                                               |
     | `NSNumber`                        | Complete        | Incomplete    |                                                                               |
     | `NSConcreteValue`                 | N/A             | N/A           | For internal use only                                                         |
     | `NSSpecialValue`                  | N/A             | N/A           | For internal use only                                                         |
diff --git a/Foundation/NSAffineTransform.swift b/Foundation/NSAffineTransform.swift
index 873e3b4..58b12c4 100644
--- a/Foundation/NSAffineTransform.swift
+++ b/Foundation/NSAffineTransform.swift
@@ -282,18 +282,66 @@
 open class NSAffineTransform : NSObject, NSCopying, NSSecureCoding {
     
     open func encode(with aCoder: NSCoder) {
-        NSUnimplemented()
+        guard aCoder.allowsKeyedCoding else {
+            preconditionFailure("Unkeyed coding is unsupported.")
+        }
+        
+        let array = [
+            Float(transformStruct.m11),
+            Float(transformStruct.m12),
+            Float(transformStruct.m21),
+            Float(transformStruct.m22),
+            Float(transformStruct.tX),
+            Float(transformStruct.tY),
+        ]
+        
+        array.withUnsafeBytes { pointer in
+            aCoder.encodeValue(ofObjCType: "[6f]", at: UnsafeRawPointer(pointer.baseAddress!))
+        }
     }
+    
     open func copy(with zone: NSZone? = nil) -> Any {
         return NSAffineTransform(transform: self)
     }
+    
     // Necessary because `NSObject.copy()` returns `self`.
     open override func copy() -> Any {
         return copy(with: nil)
     }
+    
     public required init?(coder aDecoder: NSCoder) {
-        NSUnimplemented()
+        guard aDecoder.allowsKeyedCoding else {
+            preconditionFailure("Unkeyed coding is unsupported.")
+        }
+        
+        let pointer = UnsafeMutableRawPointer.allocate(bytes: MemoryLayout<Float>.stride * 6, alignedTo: 1)
+        defer {
+            pointer.deallocate(bytes: MemoryLayout<Float>.stride * 6, alignedTo: 1)
+        }
+        aDecoder.decodeValue(ofObjCType: "[6f]", at: pointer)
+        
+        let floatPointer = pointer.bindMemory(to: Float.self, capacity: 6)
+        let m11 = floatPointer[0]
+        let m12 = floatPointer[1]
+        let m21 = floatPointer[2]
+        let m22 = floatPointer[3]
+        let tX = floatPointer[4]
+        let tY = floatPointer[5]
+
+        self.transformStruct = AffineTransform(m11: CGFloat(m11), m12: CGFloat(m12),
+                                               m21: CGFloat(m21), m22: CGFloat(m22),
+                                               tX: CGFloat(tX), tY: CGFloat(tY))
     }
+    
+    open override func isEqual(_ object: Any?) -> Bool {
+        if let other = object as? NSAffineTransform {
+            return other === self
+                || (other.transformStruct == self.transformStruct)
+        }
+        
+        return false
+    }
+    
     public static var supportsSecureCoding: Bool {
         return true
     }
diff --git a/TestFoundation/TestNSAffineTransform.swift b/TestFoundation/TestNSAffineTransform.swift
index 914fbd7..cdbffe2 100644
--- a/TestFoundation/TestNSAffineTransform.swift
+++ b/TestFoundation/TestNSAffineTransform.swift
@@ -38,6 +38,8 @@
             ("test_AppendTransform", test_AppendTransform),
             ("test_PrependTransform", test_PrependTransform),
             ("test_TransformComposition", test_TransformComposition),
+            ("test_Equal", test_Equal),
+            ("test_NSCoding", test_NSCoding),
         ]
     }
     
@@ -343,6 +345,21 @@
             XCTAssertEqual(ref.hashValue, val.hashValue)
         }
     }
+    
+    func test_Equal() {
+        let transform = NSAffineTransform()
+        let transform1 = NSAffineTransform()
+        
+        XCTAssertEqual(transform1, transform)
+        XCTAssertFalse(transform === transform1)
+    }
+    
+    func test_NSCoding() {
+        let transformA = NSAffineTransform()
+        transformA.scale(by: 2)
+        let transformB = NSKeyedUnarchiver.unarchiveObject(with: NSKeyedArchiver.archivedData(withRootObject: transformA)) as! NSAffineTransform
+        XCTAssertEqual(transformA, transformB, "Archived then unarchived `NSAffineTransform` must be equal.")
+    }
 }
 
 extension NSAffineTransform {