public async Task SerializeAsync(Stream stream, object message, Type type, CancellationToken cancellationToken = default) { using (var serializedMemory = SerializeCore(message, type)) { var uncompressed = serializedMemory.Memory; var compressedBuff = ArrayPool <byte> .Shared.Rent(LZ4Codec.MaximumOutputSize(uncompressed.Length) + HeaderLength); try { //write body, skip header var compressedLength = LZ4Codec.Encode( uncompressed.Span, new Span <byte>(compressedBuff, HeaderLength, compressedBuff.Length - HeaderLength)); //write header var offset = 0; SerializerBinary.WriteByte(ref compressedBuff, ref offset, Header); SerializerBinary.WriteInt32Fixed(ref compressedBuff, ref offset, compressedLength); SerializerBinary.WriteInt32Fixed(ref compressedBuff, ref offset, uncompressed.Length); await stream.WriteAsync(compressedBuff, 0, compressedLength + HeaderLength, cancellationToken).ConfigureAwait(false); } finally { ArrayPool <byte> .Shared.Return(compressedBuff); } } }
public void Serialize(ref byte[] buffer, ref int offset, IPAddress value) { var isIPv4 = value.AddressFamily == AddressFamily.InterNetwork; SerializerBinary.WriteByte(ref buffer, ref offset, (byte)(isIPv4 ? 0 : 1)); var ip = value.GetAddressBytes(); for (var i = 0; i < ip.Length; i++) { SerializerBinary.WriteByte(ref buffer, ref offset, ip[i]); } }
public void Serialize(ref byte[] buffer, ref int offset, Color value) { bool isKnown = value.IsKnownColor; SerializerBinary.WriteByte(ref buffer, ref offset, isKnown ? (byte)1 : (byte)0); if (isKnown) { int knownColor = (int)value.ToKnownColor(); SerializerBinary.WriteInt32Fixed(ref buffer, ref offset, knownColor); } else { SerializerBinary.WriteInt32Fixed(ref buffer, ref offset, value.ToArgb()); } }
public void Serialize(ref byte[] buffer, ref int offset, Type type) { // Null if (type == null) { SerializerBinary.WriteUInt32Bias(ref buffer, ref offset, Null, Bias); return; } var typeCache = _serializer.InstanceData.TypeCache; // Existing if (typeCache.TryGetExistingObjectId(type, out int id)) { SerializerBinary.WriteUInt32Bias(ref buffer, ref offset, id, Bias); return; } // Mode: New // Is it a composite type that we have to split into its parts? (aka any generic) bool isClosed = !type.ContainsGenericParameters; if (isClosed && type.IsGenericType) { SerializerBinary.WriteUInt32Bias(ref buffer, ref offset, NewGeneric, Bias); // Split and write // Base var baseType = type.GetGenericTypeDefinition(); Serialize(ref buffer, ref offset, baseType); // Args var genericArgs = type.GetGenericArguments(); SerializerBinary.WriteByte(ref buffer, ref offset, (byte)(genericArgs.Length)); // We need count. Ex: Action<T1> and Action<T1, T2> share the name for (int i = 0; i < genericArgs.Length; i++) { Serialize(ref buffer, ref offset, genericArgs[i]); } // Register composite type typeCache.RegisterObject(type); } else { SerializerBinary.WriteUInt32Bias(ref buffer, ref offset, NewSingle, Bias); // Open generic, something that can be serialized alone var typeName = _typeBinder.GetBaseName(type); // Name SerializerBinary.WriteString(ref buffer, ref offset, typeName); // Register single type typeCache.RegisterObject(type); } // todo: do we put this only in the if or else part? or is it ok here? it should be ok, since we want to embed the schema of every type if (_serializer.Config.VersionTolerance == VersionTolerance.AutomaticEmbedded) { if (!CerasSerializer.FrameworkAssemblies.Contains(type.Assembly)) { _serializer.WriteSchemaForType(ref buffer, ref offset, type); } } }
public void Serialize(ref byte[] buffer, ref int offset, Type type) { // Null if (type == null) { SerializerBinary.WriteUInt32Bias(ref buffer, ref offset, Null, Bias); return; } var typeCache = _serializer.InstanceData.TypeCache; // Existing if (typeCache.TryGetExistingObjectId(type, out int id)) { SerializerBinary.WriteUInt32Bias(ref buffer, ref offset, id, Bias); return; } // Mode: New // Is it a composite type that we have to split into its parts? (aka any generic) bool isClosed = !type.ContainsGenericParameters; if (isClosed && type.IsGenericType) { SerializerBinary.WriteUInt32Bias(ref buffer, ref offset, NewComposite, Bias); // Split and write // Base var baseType = type.GetGenericTypeDefinition(); Serialize(ref buffer, ref offset, baseType); // Args var genericArgs = type.GetGenericArguments(); SerializerBinary.WriteByte(ref buffer, ref offset, (byte)(genericArgs.Length)); // We need count. Ex: Action<T1> and Action<T1, T2> share the name. for (int i = 0; i < genericArgs.Length; i++) { Serialize(ref buffer, ref offset, genericArgs[i]); } // Register composite type typeCache.RegisterObject(type); } else { SerializerBinary.WriteUInt32Bias(ref buffer, ref offset, NewSingle, Bias); // Open generic, something that can be serialized alone var typeName = _typeBinder.GetBaseName(type); // Name SerializerBinary.WriteString(ref buffer, ref offset, typeName); // Register single type typeCache.RegisterObject(type); } }
public void Serialize(ref byte[] buffer, ref int offset, T member) { // Declaring type _typeFormatter.Serialize(ref buffer, ref offset, member.DeclaringType); byte bindingData = 0; switch (member.MemberType) { // Write all the data we need to resolve overloads case MemberTypes.Constructor: case MemberTypes.Method: var method = (MethodBase)(MemberInfo)member; if (method.ContainsGenericParameters) { throw new ArgumentException($"The method or constructor '{method.DeclaringType?.FullName}.{method.Name}' can not be serialized because it is not closed. If you need this functionality (or don't know what this means) please report an issue on GitHub."); } bindingData = PackBindingData(method.IsStatic, ReflectionTypeToCeras(member.MemberType)); // 1. Binding data SerializerBinary.WriteByte(ref buffer, ref offset, bindingData); // 2. Method Name _stringFormatter.Serialize(ref buffer, ref offset, method.Name); // 3. Parameters var args = method.GetParameters(); SerializerBinary.WriteInt32(ref buffer, ref offset, args.Length); for (int i = 0; i < args.Length; i++) { _typeFormatter.Serialize(ref buffer, ref offset, args[i].ParameterType); } break; case MemberTypes.Property: PropertyInfo prop = (PropertyInfo)(MemberInfo)member; bindingData = PackBindingData(prop.GetAccessors(true)[0].IsStatic, ReflectionTypeToCeras(member.MemberType)); // 1. Binding data SerializerBinary.WriteByte(ref buffer, ref offset, bindingData); // 2. Property Name _stringFormatter.Serialize(ref buffer, ref offset, prop.Name); // 3. Property Type _typeFormatter.Serialize(ref buffer, ref offset, prop.PropertyType); break; case MemberTypes.Field: FieldInfo field = (FieldInfo)(MemberInfo)member; bindingData = PackBindingData(field.IsStatic, ReflectionTypeToCeras(member.MemberType)); // 1. Binding data SerializerBinary.WriteByte(ref buffer, ref offset, bindingData); // 2. Field Name _stringFormatter.Serialize(ref buffer, ref offset, field.Name); // 3. Field Type _typeFormatter.Serialize(ref buffer, ref offset, field.FieldType); break; case MemberTypes.TypeInfo: case MemberTypes.NestedType: // This should never happen, because root types as well as nested types are simply "Type", // so they should be handled by the TypeFormatter! goto default; default: throw new ArgumentOutOfRangeException("Cannot serialize member type '" + member.MemberType + "'"); } }
public void Serialize(ref byte[] buffer, ref int offset, T member) { // Declaring type _typeFormatter.Serialize(ref buffer, ref offset, member.DeclaringType); byte bindingData = 0; switch (member.MemberType) { // Write all the data we need to resolve overloads case MemberTypes.Constructor: case MemberTypes.Method: var method = (MethodBase)(MemberInfo)member; bindingData = PackBindingData(method.IsStatic, ReflectionTypeToCeras(member.MemberType)); // 1. Binding data SerializerBinary.WriteByte(ref buffer, ref offset, bindingData); // 2. Method Name _stringFormatter.Serialize(ref buffer, ref offset, method.Name); // todo: parameter count can be merged into the unused bits of bindingData, but so much bit-packing makes things more complicated than they need to be; // it's extremely unlikely that anyone would notice the savings, even if they'd serialize tons of MemberInfos // 3. Parameters var args = method.GetParameters(); SerializerBinary.WriteInt32(ref buffer, ref offset, args.Length); for (int i = 0; i < args.Length; i++) { _typeFormatter.Serialize(ref buffer, ref offset, args[i].ParameterType); } break; case MemberTypes.Property: PropertyInfo prop = (PropertyInfo)(MemberInfo)member; bindingData = PackBindingData(prop.GetAccessors(true)[0].IsStatic, ReflectionTypeToCeras(member.MemberType)); // 1. Binding data SerializerBinary.WriteByte(ref buffer, ref offset, bindingData); // 2. Property Name _stringFormatter.Serialize(ref buffer, ref offset, prop.Name); // 3. Property Type _typeFormatter.Serialize(ref buffer, ref offset, prop.PropertyType); break; case MemberTypes.Field: FieldInfo field = (FieldInfo)(MemberInfo)member; bindingData = PackBindingData(field.IsStatic, ReflectionTypeToCeras(member.MemberType)); // 1. Binding data SerializerBinary.WriteByte(ref buffer, ref offset, bindingData); // 2. Field Name _stringFormatter.Serialize(ref buffer, ref offset, field.Name); // 3. Field Type _typeFormatter.Serialize(ref buffer, ref offset, field.FieldType); break; case MemberTypes.TypeInfo: case MemberTypes.NestedType: // This should never happen, because root types as well as nested types are simply "Type", // so they should be handled by the TypeFormatter! goto default; default: throw new ArgumentOutOfRangeException("Cannot serialize member type '" + member.MemberType + "'"); } }
public void Serialize(ref byte[] buffer, ref int offset, sbyte value) { SerializerBinary.WriteByte(ref buffer, ref offset, (byte)value); }