blob: 3f77a43d10253a99cf62cd73332baf886faa55ec [file] [log] [blame]
/*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
namespace DotPulsar.Internal.Compression
{
using DotPulsar.Internal.Abstractions;
using System;
using System.Buffers;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
public static class SnappyCompression
{
public delegate byte[] Decode(ReadOnlySpan<byte> source);
public delegate byte[] Encode(ReadOnlySpan<byte> source);
public static bool TryLoading(out ICompressorFactory? compressorFactory, out IDecompressorFactory? decompressorFactory)
{
try
{
var assembly = Assembly.Load("IronSnappy");
var definedTypes = assembly.DefinedTypes.ToArray();
var snappy = FindSnappy(definedTypes);
var methods = snappy.GetMethods(BindingFlags.Public | BindingFlags.Static);
var decode = FindDecode(methods);
var encode = FindEncode(methods);
compressorFactory = new CompressorFactory(PulsarApi.CompressionType.Snappy, () => new Compressor(CreateCompressor(encode)));
decompressorFactory = new DecompressorFactory(PulsarApi.CompressionType.Snappy, () => new Decompressor(CreateDecompressor(decode)));
return true;
}
catch
{
// Ignore
}
compressorFactory = null;
decompressorFactory = null;
return false;
}
private static TypeInfo FindSnappy(IEnumerable<TypeInfo> types)
{
const string fullName = "IronSnappy.Snappy";
foreach (var type in types)
{
if (type.FullName is null || !type.FullName.Equals(fullName))
continue;
if (type.IsPublic && type.IsClass && type.IsAbstract && type.IsSealed)
return type;
break;
}
throw new Exception($"{fullName} as a public and static class was not found");
}
private static Decode FindDecode(MethodInfo[] methods)
{
const string name = "Decode";
foreach (var method in methods)
{
if (method.Name != name || method.ReturnType != typeof(byte[]))
continue;
var parameters = method.GetParameters();
if (parameters.Length != 1)
continue;
if (parameters[0].ParameterType != typeof(ReadOnlySpan<byte>))
continue;
return (Decode) method.CreateDelegate(typeof(Decode));
}
throw new Exception($"A method with the name '{name}' matching the delegate was not found");
}
private static Encode FindEncode(MethodInfo[] methods)
{
const string name = "Encode";
foreach (var method in methods)
{
if (method.Name != name || method.ReturnType != typeof(byte[]))
continue;
var parameters = method.GetParameters();
if (parameters.Length != 1)
continue;
if (parameters[0].ParameterType != typeof(ReadOnlySpan<byte>))
continue;
return (Encode) method.CreateDelegate(typeof(Encode));
}
throw new Exception($"A method with the name '{name}' matching the delegate was not found");
}
private static Func<ReadOnlySequence<byte>, int, ReadOnlySequence<byte>> CreateDecompressor(Decode decompress)
=> (source, size) => new ReadOnlySequence<byte>(decompress(source.ToArray()));
private static Func<ReadOnlySequence<byte>, ReadOnlySequence<byte>> CreateCompressor(Encode compress)
=> (source) => new ReadOnlySequence<byte>(compress(source.ToArray()));
}
}