     case InvalidNumber(lineNumber: UInt, characterNumber: UInt)
     /// End of file reached, not always an actual error.
     case EndOfFile
+}
+
+/// Errors raised while serializing to a JSON string
+public enum JSONSerializeError: ErrorType {
+    /// Some unknown error, usually indicates something not yet implemented.
+    case Unknown
+    /// A number not supported by the JSON spec was encounterd, like infinity or NaN.
+    case InvalidNumber
 }
 
 extension JSONParseError: CustomStringConvertible {

    "r".unicodeScalars.first!: carriageReturn,
    "t".unicodeScalars.first!: tabCharacter
]

    }
}

// MARK: JSONSerializer Internals
extension JSONSerializer {
    
    func serializeValue(value: JSONValue) throws {
        switch value {
        case .JSONNumber(let nt):
            switch nt {
            case .JSONFractional(let f):
                try serializeDouble(f)
            case .JSONIntegral(let i):
                serializeInt64(i)
            }
        case .JSONNull:
            serializeNull()
        case .JSONString(let s):
            serializeString(s)
        case .JSONObject(let obj):
            try serializeObject(obj)
        case .JSONBool(let b):
            serializeBool(b)
        case .JSONArray(let a):
            try serializeArray(a)
        }
    }
    
    func serializeObject(obj: [String : JSONValue]) throws {
        output.append(leftCurlyBracket)
        var i = 0
        for (key, value) in obj {
            serializeString(key)
            output.append(colon)
            try serializeValue(value)
            i++
            if i != obj.count {
                output.append(comma)
            }
        }
        output.append(rightCurlyBracket)
    }
    
    func serializeArray(arr: [JSONValue]) throws {
        output.append(leftSquareBracket)
        var i = 0
        for val in arr {
            try serializeValue(val)
            i++
            if i != arr.count {
                output.append(comma)
            }
        }
        output.append(rightSquareBracket)
    }
    
    func serializeString(str: String) {
        output.append(quotationMark)
        var generator = str.unicodeScalars.generate()
        while let scalar = generator.next() {
            switch scalar.value {
            case 0x0000...0x001F:
                output.append(reverseSolidus)
                switch scalar {
                case tabCharacter:
                    output.appendContentsOf("t")
                case carriageReturn:
                    output.appendContentsOf("r")
                case lineFeed:
                    output.appendContentsOf("n")
                case quotationMark:
                    output.append(quotationMark)
                case backspace:
                    output.appendContentsOf("b")
                case solidus:
                    output.append(solidus)
                default:
                    output.appendContentsOf("u")
                    output.append(hexScalars[Int(scalar.value) & 0xF000 >> 12])
                    output.append(hexScalars[Int(scalar.value) & 0x0F00 >> 8])
                    output.append(hexScalars[Int(scalar.value) & 0x00F0 >> 4])
                    output.append(hexScalars[Int(scalar.value) & 0x000F >> 0])
                }
            default:
                output.append(scalar)
            }
        }
        output.append(quotationMark)
    }
    
    func serializeDouble(f: Double) throws {
        if f.isNaN || f.isInfinite {
            throw JSONSerializeError.InvalidNumber
        } else {
            // TODO: Is CustomStringConvertible for number types affected by locale?
            // TODO: Is CustomStringConvertible for Double fast?
            output.appendContentsOf(f.description)
        }
    }
    
    func serializeInt64(i: Int64) {
        // TODO: Is CustomStringConvertible for number types affected by locale?
        output.appendContentsOf(i.description)
    }
    
    func serializeBool(bool: Bool) {
        switch bool {
        case true:
            output.appendContentsOf("true")
        case false:
            output.appendContentsOf("false")
        }
    }
    
    func serializeNull() {
        output.appendContentsOf("null")
    }
}


private let leftSquareBracket = UnicodeScalar(0x005b)
private let leftCurlyBracket = UnicodeScalar(0x007b)
