Skip to content

Commit

Permalink
Experimental support for dynamic/object
Browse files Browse the repository at this point in the history
  • Loading branch information
optimus-code committed Aug 18, 2024
1 parent 3d3d300 commit 1c60591
Show file tree
Hide file tree
Showing 10 changed files with 199 additions and 22 deletions.
6 changes: 1 addition & 5 deletions RmSharp.Tests/Converters/Double.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,7 @@ public class Double
{
private readonly byte[] _rubyMarshalData = new byte[]
{
(byte)RubyMarshalToken.Double, // Token indicating a double
0x08, // Length of the string "1.2\0\0\0\0" (8 bytes total)
0x31, // '1' in ASCII
0x2E, // '.' in ASCII
0x32, // '2' in ASCII
( byte ) RubyMarshalToken.Double, 0x08, 0x31, 0x2E, 0x32
};

private readonly double _expectedValue = 1.2;
Expand Down
41 changes: 41 additions & 0 deletions RmSharp.Tests/Converters/Dynamic.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
using RmSharp.Converters;
using RmSharp.Tokens;

namespace RmSharp.Tests.Converters
{
[TestClass]
public class Dynamic
{
private readonly byte[] _rubyMarshalData = new byte[] { ( byte ) RubyMarshalToken.Fixnum, 0x02, 0xD2, 0x04 };
private readonly dynamic _expectedValue = 1234;

[TestMethod]
public void Read( )
{
var converter = RmConverterFactory.GetConverter( _expectedValue.GetType( ) );
using ( var memoryStream = new MemoryStream( _rubyMarshalData ) )
using ( var reader = new BinaryReader( memoryStream ) )
{
var result = converter.Read( reader );

Assert.IsNotNull( result );
Assert.IsInstanceOfType( result, _expectedValue.GetType( ) );
Assert.AreEqual( _expectedValue, result );
}
}

[TestMethod]
public void Write( )
{
var converter = RmConverterFactory.GetConverter( _expectedValue.GetType( ) );
using ( var memoryStream = new MemoryStream( ) )
using ( var writer = new BinaryWriter( memoryStream ) )
{
converter.Write( writer, _expectedValue );

byte[] writtenData = memoryStream.ToArray( );
CollectionAssert.AreEqual( _rubyMarshalData, writtenData );
}
}
}
}
55 changes: 55 additions & 0 deletions RmSharp.Tests/Converters/DynamicArray.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
using RmSharp.Converters;
using RmSharp.Tokens;

namespace RmSharp.Tests.Converters
{
[TestClass]
public class DyamicArray
{
private readonly byte[] _rubyMarshalData = new byte[] {

( byte ) RubyMarshalToken.Array, 0x0A,
( byte ) RubyMarshalToken.Fixnum, 0x02, 0xD2, 0x04,
( byte ) RubyMarshalToken.String, 0x10, 0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x20, 0x57, 0x6f, 0x72, 0x6c, 0x64,
( byte ) RubyMarshalToken.Fixnum, 0x02, 0xD2, 0x04,
( byte ) RubyMarshalToken.Fixnum, 0x02, 0xD2, 0x04,
( byte ) RubyMarshalToken.Double, 0x08, 0x31, 0x2E, 0x32
};

private readonly dynamic[] _expectedValue = [1234, "Hello World", 1234, 1234, 1.2];

[TestMethod]
public void Read( )
{
var converter = RmConverterFactory.GetConverter( _expectedValue.GetType() );
using ( var memoryStream = new MemoryStream( _rubyMarshalData ) )
using ( var reader = new BinaryReader( memoryStream ) )
{
var result = ( dynamic[] ) converter.Read( reader );

Assert.IsNotNull( result );
Assert.IsInstanceOfType( result, _expectedValue.GetType( ) );

for ( var i = 0; i < result.Length; i++ )
{
if ( result[i] != _expectedValue[i] )
Assert.Fail( $"Item at index '{i}' is not equal to '{_expectedValue[i]}' got '{result[i]}'." );
}
}
}

[TestMethod]
public void Write( )
{
var converter = RmConverterFactory.GetConverter( _expectedValue.GetType( ) );
using ( var memoryStream = new MemoryStream( ) )
using ( var writer = new BinaryWriter( memoryStream ) )
{
converter.Write( writer, _expectedValue );

byte[] writtenData = memoryStream.ToArray( );
CollectionAssert.AreEqual( _rubyMarshalData, writtenData );
}
}
}
}
16 changes: 6 additions & 10 deletions RmSharp.Tests/RmSharp.Tests.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,12 @@
<IsTestProject>true</IsTestProject>
</PropertyGroup>

<ItemGroup>
<Compile Remove="Data\**" />
<EmbeddedResource Remove="Data\**" />
<None Remove="Data\**" />
</ItemGroup>

<ItemGroup>
<PackageReference Include="coverlet.collector" Version="6.0.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.8.0" />
Expand All @@ -24,14 +30,4 @@
<Using Include="Microsoft.VisualStudio.TestTools.UnitTesting" />
</ItemGroup>

<ItemGroup>
<Folder Include="Data\" />
</ItemGroup>

<ItemGroup>
<None Update="Data\States.rxdata">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
</ItemGroup>

</Project>
39 changes: 39 additions & 0 deletions RmSharp/Converters/DynamicConverter.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
using RmSharp.Extensions;
using RmSharp.Tokens;
using System;
using System.IO;

namespace RmSharp.Converters
{
public class DynamicConverter : RmConverter
{
public override object Read( BinaryReader reader )
{
// Peek the byte to find out a token to process
if ( reader.PeekByte( out var byteValue ) )
{
if ( Enum.IsDefined( typeof( RubyMarshalToken ), byteValue ) )
{
var tokenConverter = RmConverterFactory.GetConverter( ( RubyMarshalToken ) byteValue );

if ( tokenConverter != null )
{
return tokenConverter.Read( reader );
}
}
}

return null;
}

public override void Write( BinaryWriter writer, object instance )
{
var converter = RmConverterFactory.GetConverter( instance.GetType() );

if ( converter != null )
{
converter.Write( writer, instance );
}
}
}
}
54 changes: 52 additions & 2 deletions RmSharp/Converters/RmConverterFactory.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
using RmSharp.Converters.Types;
using RmSharp.Converters.Types.Basic;
using RmSharp.Tokens;
using System;
using System.Collections.Generic;
using System.Dynamic;
using System.Numerics;
using System.Text.RegularExpressions;

Expand Down Expand Up @@ -32,11 +34,58 @@ public static SymbolConverter SymbolConverter
{ typeof( ulong ), new UInt64Converter( ) },
};


private static readonly Dictionary<RubyMarshalToken, RmTypeConverter> _tokenMap =
new Dictionary<RubyMarshalToken, RmTypeConverter>
{
{ RubyMarshalToken.Bignum, _typeConverters[typeof( BigInteger )]},
{ RubyMarshalToken.True, _typeConverters[typeof( bool )]},
{ RubyMarshalToken.False, _typeConverters[typeof( bool )]},
{ RubyMarshalToken.Double, _typeConverters[typeof( double )]},
{ RubyMarshalToken.Fixnum, _typeConverters[typeof( long )]},
{ RubyMarshalToken.String, _typeConverters[typeof( string )]}
};

private static readonly Dictionary<Type, RmTypeConverter> _classConverters = [];
private static readonly DynamicConverter _dynamicConverter = new( );

public static RmTypeConverter GetConverter( RubyMarshalToken token )
{
if ( _tokenMap.TryGetValue( token, out var converter ) )
return converter;

if ( token == RubyMarshalToken.Array )
{
return new ListConverter( typeof( List<dynamic> ) );
}
else if ( token == RubyMarshalToken.Hash )
{
return new DictionaryConverter( typeof( Dictionary<dynamic, dynamic> ) );
}
else if ( token == RubyMarshalToken.Object )
{
// Handle this, it'll need to find the appropriate type based on name...

//if ( _classConverters.TryGetValue( type, out converter ) )
//{
// return converter;
//}

public static RmTypeConverter GetConverter( Type type )
//converter = new ClassConverter( type );
//_classConverters.Add( type, converter );
//return converter;
}

return null;
}

public static RmConverter GetConverter( Type type )
{
if ( _typeConverters.TryGetValue( type, out var converter ) )
if ( typeof( object ) == type || typeof( IDynamicMetaObjectProvider ).IsAssignableFrom( type ) )
{
return _dynamicConverter;
}
else if ( _typeConverters.TryGetValue( type, out var converter ) )
{
return converter;
}
Expand All @@ -63,6 +112,7 @@ public static RmTypeConverter GetConverter( Type type )
_classConverters.Add( type, converter );
return converter;
}

return null;
}

Expand Down
2 changes: 1 addition & 1 deletion RmSharp/Converters/Types/ArrayConverter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ namespace RmSharp.Converters.Types
{
public class ArrayConverter : RmTypeConverter
{
private readonly RmTypeConverter _elementConverter;
private readonly RmConverter _elementConverter;

public ArrayConverter( Type type ) : base( type )
{
Expand Down
4 changes: 2 additions & 2 deletions RmSharp/Converters/Types/DictionaryConverter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@ namespace RmSharp.Converters.Types
{
public class DictionaryConverter : RmTypeConverter
{
private readonly RmTypeConverter _keyConverter;
private readonly RmTypeConverter _valueConverter;
private readonly RmConverter _keyConverter;
private readonly RmConverter _valueConverter;

public DictionaryConverter( Type type ) : base( type )
{
Expand Down
2 changes: 1 addition & 1 deletion RmSharp/Converters/Types/ListConverter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ namespace RmSharp.Converters.Types
{
public class ListConverter : RmTypeConverter
{
private readonly RmTypeConverter _elementConverter;
private readonly RmConverter _elementConverter;

public ListConverter( Type type ) : base( type )
{
Expand Down
2 changes: 1 addition & 1 deletion RmSharp/RmSharp.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@

<PropertyGroup>
<PackageId>RmSharp</PackageId>
<Version>0.0.1</Version>
<Version>0.0.2</Version>
<Authors>optimus-code;HNIdesu</Authors>
<Product>RmSharp</Product>
<Description>RmSharp is a .NET library for handling Ruby Marshal data structures, providing essential functionalities for reading, writing, and manipulating Ruby Marshal files.</Description>
Expand Down

0 comments on commit 1c60591

Please sign in to comment.