Привет всем,
Я работал над системой Node последние несколько ночей и наткнулся на небольшой блокпост (опять же XD)
Ниже большой кусок кода, который обрабатывает заглушки (которые могут состоять из различных типов данных) и узлов, которые содержат заглушки и могут что-то делать с данными из заглушек. Он был скопирован с игровой площадки, поэтому должен "работать", если вставить в него.
В настоящее время я застрял на функции Execution в AddNode , что могло бы получить доступ к данным из двух разъемов, сложить их вместе, а затем установить эти данные на выходной разъем. Узел должен иметь возможность обрабатывать создание экземпляров с различными типами, поэтому он использует Generics.
Вы можете увидеть кучу закомментированных строк, поскольку я пробовал другой сценарий ios. Я думал, что попробую сохранить Generi c Type, а затем смогу использовать это для преобразования значения и затем сложить их вместе, но похоже, что это не работает.
Я все еще очень новичок в мир Swift, это мой проект «Испытай огонь и учись». Если вы заметили какой-либо плохой / вонючий код или что-то, что можно было бы сделать лучше, пожалуйста, упомяните об этом. сделали лучше, или у вас есть лучшее решение.
protocol PlugValue {
init()
}
extension Int: PlugValue { }
extension Float: PlugValue { }
extension Double: PlugValue { }
extension SIMD3: PlugValue where Scalar == Int32 { }
//extension Array: PlugValue {}
extension Array: PlugValue where Element: PlugValue {}
class Plug<Value: PlugValue> {
public var value: Value
public var name : String
init(_ value: Value) {
self.value = value
self.name = "un-named"
}
init(_ value:Value, name:String){
self.name = name
self.value = value
}
}
protocol AnyPlug:class {
var anyValue: PlugValue { get set}
var name: String { get set }
}
extension AnyPlug {
subscript <Value: PlugValue> (type: Value.Type = Value.self) -> Value {
anyValue as? Value ?? .init()
}
func callAsFunction<Value: PlugValue>(_ type: Value.Type = Value.self) -> Value {
anyValue as? Value ?? .init()
}
}
extension Plug: AnyPlug {
var anyValue: PlugValue {
get {
value
}
set(v) {
value = v as! Value
}
}
//var anyValue: PlugValue { value }
}
extension Plug {
enum Error: Swift.Error {
case typeMismatch
}
}
extension AnyPlug {
func callAsFunction<Value: PlugValue, Return>(_ closure:(Value) -> Return) throws {
guard let value = anyValue as? Value
else { throw Plug<Value>.Error.typeMismatch }
closure(value)
}
}
// MARK:-
class Node{
var plugs: [AnyPlug]
var name: String
init(_ name:String) {
self.name = name
plugs = []
}
func addPlug<genPlug:AnyPlug>(_ plug: genPlug){
// checks the plug name doesn't exist in the list, unique names
self.validatePlug(plug)
// Adds plug only if it doesn't exist in the list already
var found = false
for inPlg in self.plugs {
if plug === inPlg {
found = true
}
}
if !found{
self.plugs.append(plug)
}
}
func getPlug(name:String) -> [AnyPlug]{
var matchs: [AnyPlug] = []
for plg in self.plugs {
if plg.name == name { matchs.append(plg) }
}
return matchs
}
public func setPlugName<genPlug:AnyPlug>(plug: genPlug, name:String) -> String{
var newName = name
// flag to store if a name collision is found, start true, to initialise the first loop
var nameCollision = true
while nameCollision {
nameCollision = false
for existing_plg in self.plugs{
// if the names match, and makes sure one is not comparing the plug to itself.
if existing_plg.name == newName && plug !== existing_plg {
nameCollision = true
newName = nameIncrement(name: newName)
}
}
}
plug.name = newName
return newName
}
/// Checks that the plug is valid. At the moment this means checking no name collisions
private func validatePlug<genPlug:AnyPlug>(_ plug: genPlug){
_ = self.setPlugName(plug: plug, name: plug.name)
}
}
class AddNode<numericType:PlugValue> : Node{
var acceptedType:numericType.Type
var out:Plug<numericType>?
public override required init(_ name:String="AddNode"){
self.acceptedType = numericType.self
super.init(name)
self.initPlugs()
}
func initPlugs() {
let default_value:numericType
if numericType.self == Double.self{
default_value = 0.0 as! numericType
}
else
if numericType.self == Float.self{
default_value = Float(0.0) as! numericType
}
else { default_value = 0 as! numericType}
// Input plugs
let plg_in_1 = Plug(default_value, name:"value_1" )
let plg_in_2 = Plug(default_value, name:"value_2" )
// Output plugs
let plg_out_1 = Plug(default_value, name:"result")
plugs.append(plg_in_1)
plugs.append(plg_in_2)
self.out = plg_out_1
}
func execute() {
var sum_value:numericType? = nil
for plg in self.plugs{
let plgVal = plg as! Plug<numericType>
if sum_value == nil{
sum_value = plgVal.value
}
else{
let tValue = plgVal[numericType.self]
numericType() + acceptedType.init(1.0)
0.0
//numericType.Type
numericType.self
let ttValue: numericType = plgVal()
numericType.self
acceptedType.self
tValue
ttValue
plg[numericType]
//tValue + 1.0
//sum_value = sum_value + plgVal.value
//sum_value =+ 2.0
//sum_value! + tValue
}
}
self.out!.value = sum_value!
}
}
/**
Performs an incrementation on a name
- Parameter name: The string that will have a number appended or incremented on the end of it.
- Returns: An incremented string
# Example:
~~~
"name" = "name_1"
"name_1" = "name_2"
*/
public func nameIncrement(name:String) -> String {
// check the name has a suffix '_#'
// if no suffix is found add one, if one is found
var new_name:String = name
if name.contains("_"){
var string_bits = name.split(separator: "_")
// the last suffix was not a number, so we can just add _1 to the end
if Int(string_bits.last!) == nil { new_name.append("_1") }
else
{
var index = Int(string_bits.last!) ?? 0
index += 1
string_bits.remove(at: string_bits.endIndex-1)
string_bits.insert(Substring(String(index)), at:string_bits.endIndex)
new_name = string_bits.joined(separator: "_")
}
}
else {
// name has no "_", so we append a 1 to the end of the name
new_name.append("_1")
}
return new_name
}
// MARK: IMPLEMENTATION USAGE
var newNode = Node("Dynamic Node")
var plg_1 = Plug(1, name:"index")
var plg_2 = Plug([2.2, 45.0, 90.1], name:"angles")
var plg_3 = Plug([0.0, 0.0, 0.0], name:"angles") // Name conflict
// Add plug to Node
newNode.addPlug(plg_1)
newNode.addPlug(plg_2)
newNode.addPlug(plg_3)
var tempPlug_1 = newNode.plugs[0]
var tempPlug_2 = newNode.plugs[2]
// How would I cast the AnyNode back into a Plug<Type>
// Is there a more straight forward way to do this, which doesn't require the creation of a new variable, and knowing the type
// Would it be possible to store the type of plug in the protocol and leverage that to cast back into a plug
// eg. var tp = tempPlug_1 as! Plug<Int>
// is there a way to hold a type in a variable so you can use it later to cast the generic type
/*
var magicType = Int // have it as a variable in the protocol?
var tp = tempPlug_1 as! Plug<magicType>
*/
var tp = tempPlug_1 as! Plug<Int>
tp === plg_1 // is true, so they are pointers to the same location, even though its a new variable and been cast
tp.value = 5
var sds = newNode.plugs[0][Int]
newNode.plugs[0].anyValue = 10
var sds2 = newNode.plugs[0]
plg_1.value = 20 // best case scenario
// testing purposes to change type easier for testing
typealias caster = Double
let addNode = AddNode<caster>("newNode")
addNode.name = "Add Node"
addNode.plugs[0].anyValue = caster(2.0)
addNode.plugs[1].anyValue = caster(4.0)
addNode.execute()
addNode.out
// instantiate a variable from the node type // investigation purposes
var testType = addNode.acceptedType.init(2)
testType + 2
Еще раз спасибо за внимание,
С уважением, Саймон