| /* |
| * 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())); |
| } |