//
//  NXPersonProtocol.swift
//  iOSApp-Swift
//
//  Created by 聂高涛 on 2022/2/7.
//

import UIKit



class Protocols  {
    
    func add<T:FixedWidthInteger>(x: T, y:T) -> T {
        return x + y
    }
    
    func test(){
        
        let x : Int8 = 5
        let y : Int8 = 6
        let ret = add(x: x, y: y)
        
        let x1 : Int = 5
        let y1 : Int = 6
        let ret1 = add(x: x1, y: y1)
        
    }
}

struct NXStacker<Element> {
    private var elements  = [Element]()
    
    private(set) var count = 0

    mutating func push(_ e:Element) {
        count += 1
        elements.append(e)
    }

    mutating func pop() -> Element? {
        if elements.isEmpty {return nil}
        count -= 1
        return elements.removeLast()
    }
    
    func index(of index:Int) -> Element? {
        if index >= 0 && index < elements.count {
            return elements[index]
        }
        return nil
    }
}

protocol StackerProtocol {
    associatedtype Element
    var count : Int {get}
    mutating func push(_ e: Element)
    mutating func pop() -> Element?
    func index(of index:Int) -> Element?
}


func compare<T1:StackerProtocol, T2:StackerProtocol>(_ lhs:T1, _ rhs:T2) -> Bool where T1.Element: Equatable, T2.Element: Equatable, T1.Element == T2.Element  {
    guard lhs.count == rhs.count else {return false}
    for i in 0 ..< lhs.count {
        if lhs.index(of: i) != rhs.index(of: i) {
            return false
        }
    }
    return true
}

protocol NXPersonProtocol {
    
}


protocol NXDescriptionProtocol  {
    var description : String {get}
//    var debugDescription : String {get set}
    
    func toggle()
}

extension NXDescriptionProtocol {
    func toggle() {
        NX.print("NXDescriptionProtocol")
    }
}



extension NXPerson : NXDescriptionProtocol {
    var description: String {
        return "id:\(self.id), name:\(self.name)"
    }
    
    func toggle() {
        NX.print("NXPerson")
    }
}

//extension NXAnimal : NXDescriptionProtocol {
//    var description: String {
//        return "id:\(self.id), name:\(self.name)"
//    }
//
//    var debugDescription: String {
//        set{
//
//        }
//        get{
//            return ""
//        }
//    }
//
//    mutating func toggle() {
//
//    }
//}

func testProtocol() {
    let p : NXDescriptionProtocol = NXPerson(1, "Swift")
    p.toggle()
}



struct User {
    var id  = 0
    var name = ""
}

struct Vip {
    var id  = 0
    var name = ""
}

protocol Fetchable {
    associatedtype Element
    func fetch(completion:((Element?, Error?) -> Void))
}

struct UserFetcher : Fetchable {
    typealias Element = User
    func fetch(completion: ((Element?, Error?) -> Void)) {
        let usr = Element(id: 0, name: "")
        completion(usr, nil)
    }
}

struct VipFetcher : Fetchable {
    typealias Element = Vip
    func fetch(completion: ((Element?, Error?) -> Void)) {
        let vip = Element(id: 0, name: "")
        completion(vip, nil)
    }
}

struct AnyFetcher<T> : Fetchable {
    typealias Element = T
    
    private let _fetchable : ((T?, Error?) -> Void) -> Void
    
    init<E:Fetchable>(fetchable:E) where E.Element == T {
        _fetchable = fetchable.fetch
    }
    
    func fetch(completion: ((T?, Error?) -> Void)) {
        _fetchable(completion)
    }
}

func test() {
    
    let fetcher = UserFetcher()
    let anyfetchable = AnyFetcher<User>(fetchable: fetcher)
    anyfetchable.fetch { value, error in
        
    }
    
    let fetcher2 = VipFetcher()
    let anyfetchable2 = AnyFetcher<Vip>(fetchable: fetcher2)
    anyfetchable2.fetch { value, error in
        
    }
    
}





