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);
}
}
}