package helpers; import haxe.ds.IntMap; import haxe.ds.StringMap; @:generic class ObjectHelper { public static function copyFields (source:T, destination:T):T { for (field in Reflect.fields (source)) { Reflect.setField (destination, field, Reflect.field (source, field)); } return destination; } public static function copyFieldsPreferObjectOverValue (source:T, destination:T):T { for (field in Reflect.fields (source)) { var do_copy = true; var exists = Reflect.hasField( destination, field ); if( exists ) { var value_source = Reflect.field (source, field); var value_dest = Reflect.field (destination, field); var type_source = Type.typeof(value_source).getName(); var type_dest = Type.typeof(value_dest).getName(); // if(LogHelper.verbose) { // LogHelper.println(field + " / existed in dest as " + type_dest + " / " + type_source ); // } //if trying to copy a non object over an object, don't if(type_source != "TObject" && type_dest == "TObject") { do_copy = false; if(LogHelper.verbose) { LogHelper.println(field + " not merged by preference" ); } } } if(do_copy) { Reflect.setField (destination, field, Reflect.field (source, field)); } } return destination; } public static function copyMissingFields (source:T, destination:T):T { for (field in Reflect.fields (source)) { if (!Reflect.hasField (destination, field)) { Reflect.setField (destination, field, Reflect.field (source, field)); } } return destination; } public static function copyUniqueFields (source:T, destination:T, defaultInstance:T):T { for (field in Reflect.fields (source)) { var value = Reflect.field (source, field); if (value != Reflect.field (defaultInstance, field)) { Reflect.setField (destination, field, value); } } return destination; } public static function deepCopy (v:T):T { if (!Reflect.isObject (v)) { // simple type return v; } else if (Std.is (v, String)) { // string return v; } else if (Std.is (v, Array)) { // array var result = Type.createInstance (Type.getClass (v), []); untyped { for (ii in 0...v.length) { result.push (deepCopy (v[ii])); } } return result; } else if (Std.is (v, StringMap)) { // hashmap var result = Type.createInstance (Type.getClass(v), []); untyped { var keys:Iterator = v.keys (); for (key in keys) { result.set (key, deepCopy (v.get (key))); } } return result; } else if (Std.is (v, IntMap)) { // integer-indexed hashmap var result = Type.createInstance (Type.getClass (v), []); untyped { var keys:Iterator = v.keys (); for (key in keys) { result.set (key, deepCopy (v.get (key))); } } return result; } else if (Std.is (v, List)) { // list //List would be copied just fine without this special case, but I want to avoid going recursive var result = Type.createInstance (Type.getClass (v), []); untyped { var iter:Iterator = v.iterator (); for (ii in iter) { result.add (ii); } } return result; } else if (Type.getClass(v) == null) { // anonymous object var obj:Dynamic = {}; for (ff in Reflect.fields (v)) { Reflect.setField (obj, ff, deepCopy (Reflect.field (v, ff))); } return obj; } else { // class var obj = Type.createEmptyInstance (Type.getClass (v)); for (ff in Reflect.fields (v)) { Reflect.setField (obj, ff, deepCopy (Reflect.field (v, ff))); } return obj; } return null; } }