public static object DeepCopy(RubyContext /*!*/ context, object obj) { using (IDisposable handle = _infiniteCopyTracker.TrackObject(obj)) { if (handle == null) { return(RubyExceptions.CreateArgumentError("unable to deep copy recursive structure")); } else { RubyContext ec = RubyUtils.GetExecutionContext(context); if (RubyUtils.IsRubyValueType(obj)) { return(obj); } object copy; // TODO: special case class objects: RubyClass classObject = obj as RubyClass; if (classObject != null) { copy = classObject.Duplicate(); } else { copy = RubySites.Allocate(context, ec.GetClassOf(obj)); } SymbolId[] names = ec.GetInstanceVariableNames(obj); RubyInstanceData newVars = (names.Length > 0) ? ec.GetInstanceData(copy) : null; foreach (SymbolId name in names) { object value; if (!ec.TryGetInstanceVariable(obj, name, out value)) { value = null; } else { value = DeepCopy(context, value); } newVars.SetInstanceVariable(name, value); } if (classObject == null) { // do any special copying needed for library types // TODO: we still need to implement copy semantics for .NET types in general IDuplicable duplicable = copy as IDuplicable; if (duplicable != null) { duplicable.InitializeFrom(obj); } } return(copy); } } }
private void WriteAnObject(object obj) { if (_recursionLimit == 0) { throw RubyExceptions.CreateArgumentError("exceed depth limit"); } if (_recursionLimit > 0) { _recursionLimit--; } if (obj is int) { int value = (int)obj; if (value < -(1 << 30) || value >= (1 << 30)) { obj = (BigInteger)value; } } // TODO: use RubyUtils.IsRubyValueType? RubySymbol sym; if (obj == null) { _writer.Write((byte)'0'); } else if (obj is bool) { _writer.Write((byte)((bool)obj ? 'T' : 'F')); } else if (obj is int) { WriteFixnum((int)obj); } else if ((sym = obj as RubySymbol) != null) { // TODO (encoding): WriteSymbol(sym.ToString(), sym.Encoding); } else { int objectRef; if (_objects.TryGetValue(obj, out objectRef)) { _writer.Write((byte)'@'); WriteInt32(objectRef); } else { objectRef = _objects.Count; _objects[obj] = objectRef; // TODO: replace with a table-driven implementation // TODO: visibility? bool implementsDump = _context.ResolveMethod(obj, "_dump", VisibilityContext.AllVisible).Found; bool implementsMarshalDump = _context.ResolveMethod(obj, "marshal_dump", VisibilityContext.AllVisible).Found; bool writeInstanceData = false; string[] instanceNames = null; if (!implementsDump && !implementsMarshalDump) { // Neither "_dump" nor "marshal_dump" writes instance vars separately instanceNames = _context.GetInstanceVariableNames(obj); if (instanceNames.Length > 0) { _writer.Write((byte)'I'); writeInstanceData = true; } } if (!implementsDump || implementsMarshalDump) { // "_dump" doesn't write "extend" info but "marshal_dump" does RubyClass theClass = _context.GetImmediateClassOf(obj); if (theClass.IsSingletonClass) { foreach (var mixin in theClass.GetMixins()) { _writer.Write((byte)'e'); WriteModuleName(mixin); } } } if (obj is double) { WriteFloat((double)obj); } else if (obj is float) { WriteFloat((double)(float)obj); } else if (obj is BigInteger) { WriteBignum((BigInteger)obj); } else if (implementsMarshalDump) { WriteUsingMarshalDump(obj); } else if (implementsDump) { WriteUsingDump(obj); } else if (obj is MutableString) { WriteString((MutableString)obj); } else if (obj is RubyArray) { WriteArray((RubyArray)obj); } else if (obj is Hash) { WriteHash((Hash)obj); } else if (obj is RubyRegex) { WriteRegex((RubyRegex)obj); } else if (obj is RubyClass) { WriteClass((RubyClass)obj); } else if (obj is RubyModule) { WriteModule((RubyModule)obj); } else if (obj is RubyStruct) { WriteStruct((RubyStruct)obj); } else if (obj is Range) { WriteRange((Range)obj); } else { if (writeInstanceData) { // Overwrite the "I"; we always have instance data _writer.BaseStream.Seek(-1, SeekOrigin.Current); } else { writeInstanceData = true; } WriteObject(obj); } if (writeInstanceData) { WriteInt32(instanceNames.Length); var encoding = _context.GetIdentifierEncoding(); foreach (string name in instanceNames) { object value; if (!_context.TryGetInstanceVariable(obj, name, out value)) { value = null; } // TODO (encoding): WriteSymbol(name, encoding); WriteAnObject(value); } } } } if (_recursionLimit >= 0) { _recursionLimit++; } }
public static RubyArray/*!*/ InstanceVariables(RubyContext/*!*/ context, object self) { string[] names = context.GetInstanceVariableNames(self); RubyArray result = new RubyArray(names.Length); foreach (string name in names) { result.Add(MutableString.Create(name)); } return result; }
public static RubyArray /*!*/ ToYamlProperties(RubyContext /*!*/ context, object self) { string[] names = context.GetInstanceVariableNames(self); Array.Sort(names); return(context.StringifyIdentifiers(names)); }
public static RubyArray/*!*/ GetInstanceVariableNames(RubyContext/*!*/ context, object self) { return context.StringifyIdentifiers(context.GetInstanceVariableNames(self)); }
public static RubyArray ToYamlProperties(RubyContext/*!*/ context, object self) { string[] names = context.GetInstanceVariableNames(self); Array.Sort(names); return context.StringifyIdentifiers(names); }