Skip to content

Commit 965fee4

Browse files
committed
Add GraphBinary4 type serializers to gremlin-dotnet
This is just the type serializers but not the message serializers which will be implemented later. Uses the same style as GraphBinary1 despite not having custom types. The "4" file suffix is used for now to help quickly differentiate between the v1 and v4 implementations but will be removed in the future when GraphBinary1 is removed.
1 parent 06532a5 commit 965fee4

30 files changed

Lines changed: 4111 additions & 0 deletions
Lines changed: 142 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,142 @@
1+
#region License
2+
3+
/*
4+
* Licensed to the Apache Software Foundation (ASF) under one
5+
* or more contributor license agreements. See the NOTICE file
6+
* distributed with this work for additional information
7+
* regarding copyright ownership. The ASF licenses this file
8+
* to you under the Apache License, Version 2.0 (the
9+
* "License"); you may not use this file except in compliance
10+
* with the License. You may obtain a copy of the License at
11+
*
12+
* http://www.apache.org/licenses/LICENSE-2.0
13+
*
14+
* Unless required by applicable law or agreed to in writing,
15+
* software distributed under the License is distributed on an
16+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17+
* KIND, either express or implied. See the License for the
18+
* specific language governing permissions and limitations
19+
* under the License.
20+
*/
21+
22+
#endregion
23+
24+
using System;
25+
26+
namespace Gremlin.Net.Structure.IO.GraphBinary4
27+
{
28+
/// <summary>
29+
/// Represents a GraphBinary 4.0 data type.
30+
/// </summary>
31+
public class DataType4 : IEquatable<DataType4>
32+
{
33+
#pragma warning disable 1591
34+
public static readonly DataType4 Int = new DataType4(0x01);
35+
public static readonly DataType4 Long = new DataType4(0x02);
36+
public static readonly DataType4 String = new DataType4(0x03);
37+
public static readonly DataType4 DateTime = new DataType4(0x04);
38+
public static readonly DataType4 Double = new DataType4(0x07);
39+
public static readonly DataType4 Float = new DataType4(0x08);
40+
public static readonly DataType4 List = new DataType4(0x09);
41+
public static readonly DataType4 Map = new DataType4(0x0A);
42+
public static readonly DataType4 Set = new DataType4(0x0B);
43+
public static readonly DataType4 Uuid = new DataType4(0x0C);
44+
public static readonly DataType4 Edge = new DataType4(0x0D);
45+
public static readonly DataType4 Path = new DataType4(0x0E);
46+
public static readonly DataType4 Property = new DataType4(0x0F);
47+
// Not yet implemented
48+
// public static readonly DataType4 Graph = new DataType4(0x10);
49+
public static readonly DataType4 Vertex = new DataType4(0x11);
50+
public static readonly DataType4 VertexProperty = new DataType4(0x12);
51+
public static readonly DataType4 Direction = new DataType4(0x18);
52+
public static readonly DataType4 T = new DataType4(0x20);
53+
public static readonly DataType4 Merge = new DataType4(0x21);
54+
public static readonly DataType4 BigDecimal = new DataType4(0x22);
55+
public static readonly DataType4 BigInteger = new DataType4(0x23);
56+
public static readonly DataType4 Byte = new DataType4(0x24);
57+
public static readonly DataType4 Binary = new DataType4(0x25);
58+
public static readonly DataType4 Short = new DataType4(0x26);
59+
public static readonly DataType4 Boolean = new DataType4(0x27);
60+
// Not yet implemented
61+
// public static readonly DataType4 Tree = new DataType4(0x2B);
62+
// public static readonly DataType4 CompositePDT = new DataType4(0xF0);
63+
// public static readonly DataType4 PrimitivePDT = new DataType4(0xF1);
64+
public static readonly DataType4 Char = new DataType4(0x80);
65+
public static readonly DataType4 Duration = new DataType4(0x81);
66+
public static readonly DataType4 Marker = new DataType4(0xFD);
67+
#pragma warning restore 1591
68+
69+
/// <summary>
70+
/// A null value for an unspecified Object value.
71+
/// </summary>
72+
public static readonly DataType4 UnspecifiedNull = new DataType4(0xFE);
73+
74+
private DataType4(int code)
75+
{
76+
TypeCode = (byte) code;
77+
}
78+
79+
/// <summary>
80+
/// Gets the type code of this data type.
81+
/// </summary>
82+
public byte TypeCode { get; }
83+
84+
/// <summary>
85+
/// Creates a new <see cref="DataType4"/> instance for the given type code.
86+
/// </summary>
87+
public static DataType4 FromTypeCode(int code)
88+
{
89+
return new DataType4(code);
90+
}
91+
92+
/// <inheritdoc />
93+
public bool Equals(DataType4? other)
94+
{
95+
if (ReferenceEquals(null, other)) return false;
96+
if (ReferenceEquals(this, other)) return true;
97+
return TypeCode == other.TypeCode;
98+
}
99+
100+
/// <inheritdoc />
101+
public override bool Equals(object? obj)
102+
{
103+
if (ReferenceEquals(null, obj)) return false;
104+
if (ReferenceEquals(this, obj)) return true;
105+
if (obj.GetType() != GetType()) return false;
106+
return Equals((DataType4) obj);
107+
}
108+
109+
/// <inheritdoc />
110+
public override int GetHashCode()
111+
{
112+
return TypeCode.GetHashCode();
113+
}
114+
115+
/// <summary>
116+
/// Determines whether two specified <see cref="DataType4"/> have the same values.
117+
/// </summary>
118+
public static bool operator ==(DataType4? first, DataType4? second)
119+
{
120+
if (ReferenceEquals(null, first))
121+
{
122+
return ReferenceEquals(null, second);
123+
}
124+
125+
return first.Equals(second);
126+
}
127+
128+
/// <summary>
129+
/// Determines whether two specified <see cref="DataType4"/> have different values.
130+
/// </summary>
131+
public static bool operator !=(DataType4? first, DataType4? second)
132+
{
133+
return !(first == second);
134+
}
135+
136+
/// <inheritdoc />
137+
public override string ToString()
138+
{
139+
return $"DataType4{{ TypeCode = {TypeCode} }}";
140+
}
141+
}
142+
}
Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
#region License
2+
3+
/*
4+
* Licensed to the Apache Software Foundation (ASF) under one
5+
* or more contributor license agreements. See the NOTICE file
6+
* distributed with this work for additional information
7+
* regarding copyright ownership. The ASF licenses this file
8+
* to you under the Apache License, Version 2.0 (the
9+
* "License"); you may not use this file except in compliance
10+
* with the License. You may obtain a copy of the License at
11+
*
12+
* http://www.apache.org/licenses/LICENSE-2.0
13+
*
14+
* Unless required by applicable law or agreed to in writing,
15+
* software distributed under the License is distributed on an
16+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17+
* KIND, either express or implied. See the License for the
18+
* specific language governing permissions and limitations
19+
* under the License.
20+
*/
21+
22+
#endregion
23+
24+
using System.IO;
25+
using System.Threading;
26+
using System.Threading.Tasks;
27+
28+
namespace Gremlin.Net.Structure.IO.GraphBinary4
29+
{
30+
/// <summary>
31+
/// Allows to deserialize objects from GraphBinary v4.
32+
/// </summary>
33+
public class GraphBinaryReader4
34+
{
35+
private readonly TypeSerializerRegistry4 _registry;
36+
37+
/// <summary>
38+
/// Initializes a new instance of the <see cref="GraphBinaryReader4" /> class.
39+
/// </summary>
40+
/// <param name="registry">The <see cref="TypeSerializerRegistry4"/> to use for deserialization.</param>
41+
public GraphBinaryReader4(TypeSerializerRegistry4? registry = null)
42+
{
43+
_registry = registry ?? TypeSerializerRegistry4.Instance;
44+
}
45+
46+
/// <summary>
47+
/// Reads only the value for a specific type <typeparamref name="T"/>.
48+
/// </summary>
49+
/// <param name="stream">The GraphBinary data to parse.</param>
50+
/// <param name="cancellationToken">The token to cancel the operation. The default value is None.</param>
51+
/// <typeparam name="T">The type of the object to read.</typeparam>
52+
/// <returns>The read value.</returns>
53+
public async Task<object?> ReadNullableValueAsync<T>(Stream stream,
54+
CancellationToken cancellationToken = default)
55+
{
56+
var typedSerializer = _registry.GetSerializerFor(typeof(T));
57+
return await typedSerializer.ReadNullableValueAsync(stream, this, cancellationToken)
58+
.ConfigureAwait(false);
59+
}
60+
61+
/// <summary>
62+
/// Reads only the value for a specific type <typeparamref name="T"/>.
63+
/// </summary>
64+
/// <param name="stream">The GraphBinary data to parse.</param>
65+
/// <param name="cancellationToken">The token to cancel the operation. The default value is None.</param>
66+
/// <typeparam name="T">The type of the object to read.</typeparam>
67+
/// <returns>The read value.</returns>
68+
public async Task<object> ReadNonNullableValueAsync<T>(Stream stream,
69+
CancellationToken cancellationToken = default)
70+
{
71+
var typedSerializer = _registry.GetSerializerFor(typeof(T));
72+
return await typedSerializer.ReadNonNullableValueAsync(stream, this, cancellationToken)
73+
.ConfigureAwait(false);
74+
}
75+
76+
/// <summary>
77+
/// Reads the type code, information and value with fully-qualified format.
78+
/// </summary>
79+
/// <param name="stream">The GraphBinary data to parse.</param>
80+
/// <param name="cancellationToken">The token to cancel the operation. The default value is None.</param>
81+
/// <returns>The read value.</returns>
82+
public async Task<object?> ReadAsync(Stream stream, CancellationToken cancellationToken = default)
83+
{
84+
var type = DataType4.FromTypeCode(await stream.ReadByteAsync(cancellationToken).ConfigureAwait(false));
85+
86+
if (type == DataType4.UnspecifiedNull)
87+
{
88+
await stream.ReadByteAsync(cancellationToken).ConfigureAwait(false); // read value byte to advance the index
89+
return null;
90+
}
91+
92+
var typeSerializer = _registry.GetSerializerFor(type);
93+
return await typeSerializer.ReadAsync(stream, this, cancellationToken).ConfigureAwait(false);
94+
}
95+
}
96+
}
Lines changed: 139 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,139 @@
1+
#region License
2+
3+
/*
4+
* Licensed to the Apache Software Foundation (ASF) under one
5+
* or more contributor license agreements. See the NOTICE file
6+
* distributed with this work for additional information
7+
* regarding copyright ownership. The ASF licenses this file
8+
* to you under the Apache License, Version 2.0 (the
9+
* "License"); you may not use this file except in compliance
10+
* with the License. You may obtain a copy of the License at
11+
*
12+
* http://www.apache.org/licenses/LICENSE-2.0
13+
*
14+
* Unless required by applicable law or agreed to in writing,
15+
* software distributed under the License is distributed on an
16+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17+
* KIND, either express or implied. See the License for the
18+
* specific language governing permissions and limitations
19+
* under the License.
20+
*/
21+
22+
#endregion
23+
24+
using System;
25+
using System.IO;
26+
using System.Threading;
27+
using System.Threading.Tasks;
28+
29+
namespace Gremlin.Net.Structure.IO.GraphBinary4
30+
{
31+
/// <summary>
32+
/// Allows to serialize objects to GraphBinary v4.
33+
/// </summary>
34+
public class GraphBinaryWriter4
35+
{
36+
private const byte ValueFlagNull = 1;
37+
private const byte ValueFlagNone = 0;
38+
39+
/// <summary>
40+
/// A <see cref="byte"/> representing the version of the GraphBinary v4 specification.
41+
/// </summary>
42+
public const byte VersionByte = 0x84;
43+
44+
private static readonly byte[] UnspecifiedNullBytes = {DataType4.UnspecifiedNull.TypeCode, 0x01};
45+
46+
private readonly TypeSerializerRegistry4 _registry;
47+
48+
/// <summary>
49+
/// Initializes a new instance of the <see cref="GraphBinaryWriter4" /> class.
50+
/// </summary>
51+
/// <param name="registry">The <see cref="TypeSerializerRegistry4"/> to use for serialization.</param>
52+
public GraphBinaryWriter4(TypeSerializerRegistry4? registry = null)
53+
{
54+
_registry = registry ?? TypeSerializerRegistry4.Instance;
55+
}
56+
57+
/// <summary>
58+
/// Writes a nullable value without including type information.
59+
/// </summary>
60+
/// <param name="value">The value to write.</param>
61+
/// <param name="stream">The stream to write to.</param>
62+
/// <param name="cancellationToken">The token to cancel the operation. The default value is None.</param>
63+
/// <returns>A task that represents the asynchronous write operation.</returns>
64+
public async Task WriteNullableValueAsync(object? value, Stream stream,
65+
CancellationToken cancellationToken = default)
66+
{
67+
if (value == null)
68+
{
69+
await WriteValueFlagNullAsync(stream, cancellationToken).ConfigureAwait(false);
70+
return;
71+
}
72+
73+
var valueType = value.GetType();
74+
var serializer = _registry.GetSerializerFor(valueType);
75+
await serializer.WriteNullableValueAsync(value, stream, this, cancellationToken).ConfigureAwait(false);
76+
}
77+
78+
/// <summary>
79+
/// Writes a non-nullable value without including type information.
80+
/// </summary>
81+
/// <param name="value">The value to write.</param>
82+
/// <param name="stream">The stream to write to.</param>
83+
/// <param name="cancellationToken">The token to cancel the operation. The default value is None.</param>
84+
/// <returns>A task that represents the asynchronous write operation.</returns>
85+
public async Task WriteNonNullableValueAsync(object value, Stream stream,
86+
CancellationToken cancellationToken = default)
87+
{
88+
if (value == null) throw new IOException($"{nameof(value)} cannot be null");
89+
var valueType = value.GetType();
90+
var serializer = _registry.GetSerializerFor(valueType);
91+
await serializer.WriteNonNullableValueAsync(value, stream, this, cancellationToken).ConfigureAwait(false);
92+
}
93+
94+
/// <summary>
95+
/// Writes an object in fully-qualified format, containing {type_code}{type_info}{value_flag}{value}.
96+
/// </summary>
97+
/// <param name="value">The value to write.</param>
98+
/// <param name="stream">The stream to write to.</param>
99+
/// <param name="cancellationToken">The token to cancel the operation. The default value is None.</param>
100+
/// <returns>A task that represents the asynchronous write operation.</returns>
101+
public async Task WriteAsync(object? value, Stream stream, CancellationToken cancellationToken = default)
102+
{
103+
if (value == null)
104+
{
105+
await stream.WriteAsync(UnspecifiedNullBytes, cancellationToken).ConfigureAwait(false);
106+
return;
107+
}
108+
109+
var valueType = value.GetType();
110+
var serializer = _registry.GetSerializerFor(valueType);
111+
112+
await stream.WriteByteAsync(serializer.DataType.TypeCode, cancellationToken).ConfigureAwait(false);
113+
await serializer.WriteAsync(value, stream, this, cancellationToken).ConfigureAwait(false);
114+
}
115+
116+
/// <summary>
117+
/// Writes a single byte representing the null value_flag.
118+
/// </summary>
119+
/// <param name="stream">The stream to write to.</param>
120+
/// <param name="cancellationToken">The token to cancel the operation. The default value is None.</param>
121+
/// <returns>A task that represents the asynchronous write operation.</returns>
122+
public async Task WriteValueFlagNullAsync(Stream stream, CancellationToken cancellationToken = default)
123+
{
124+
await stream.WriteByteAsync(ValueFlagNull, cancellationToken).ConfigureAwait(false);
125+
}
126+
127+
/// <summary>
128+
/// Writes a single byte with value 0, representing an unset value_flag.
129+
/// </summary>
130+
/// <param name="stream">The stream to write to.</param>
131+
/// <param name="cancellationToken">The token to cancel the operation. The default value is None.</param>
132+
/// <returns>A task that represents the asynchronous write operation.</returns>
133+
public async Task WriteValueFlagNoneAsync(Stream stream, CancellationToken cancellationToken = default) {
134+
await stream.WriteByteAsync(ValueFlagNone, cancellationToken).ConfigureAwait(false);
135+
}
136+
137+
138+
}
139+
}

0 commit comments

Comments
 (0)