예제 #1
0
        private void PushPendingCharactersToValue()
        {
            if (Partial.CurrentColumnIndex >= Columns.Length)
            {
                Throw.InvalidOperationException($"Unexpected column (Index={Partial.CurrentColumnIndex})");
            }

            var dataSpan = Partial.PendingAsMemory(Buffer.Buffer);

            var colIx  = Partial.CurrentColumnIndex;
            var column = Columns[colIx];

            if (column.IsRequired && dataSpan.Length == 0)
            {
                Throw.SerializationException($"Column [{column.Name}] is required, but was not found in row");
            }

            var ctx = new ReadContext(RowNumber, colIx, Columns[colIx].Name, Context);

            if (!column.Set(dataSpan.Span, in ctx, Partial.Value))
            {
                Throw.InvalidOperationException($"Could not assign value \"{Partial.PendingAsString(Buffer.Buffer)}\" to column \"{column.Name}\" (Index={Partial.CurrentColumnIndex})");
            }

            Partial.ClearBufferAndAdvanceColumnIndex();
        }
예제 #2
0
        internal ReaderStateMachine(
            MemoryPool <char> memoryPool,
            char escapeStartChar,
            char valueSeparatorChar,
            char escapeChar,
            RowEndings rowEndings,
            ReadHeaders hasHeaders,
            char?commentChar
            )
        {
            RowEndings = rowEndings;
            HasHeaders = hasHeaders;

            switch (HasHeaders)
            {
            case ReadHeaders.Always:
                CurrentState = State.Header_Start;
                break;

            case ReadHeaders.Never:
                CurrentState = State.Record_Start;
                break;

            default:
                Throw.InvalidOperationException($"Unexpected {nameof(ReadHeaders)}: {HasHeaders}");
                break;
            }

            TransitionMatrixHandle = GetTransitionMatrix(RowEndings, escapeStartChar == escapeChar).Pin();
            TransitionMatrix       = (TransitionRule *)TransitionMatrixHandle.Pointer;

            SuppressCharLookupDispose = false;
            (MinimumCharacter, CharLookupOffset, CharLookupOwner, CharLookupPin, CharLookup) =
                MakeCharacterLookup(memoryPool, escapeStartChar, valueSeparatorChar, escapeChar, commentChar);
        }
 private void AssertCanMakeReader()
 {
     if (!RowBuilder.HasValue)
     {
         Throw.InvalidOperationException($"Cannot make a reader for {typeof(T).Name}, returned {nameof(InstanceProvider)} and {nameof(DeserializableMember)}s were not sufficient.");
     }
 }
 private void AssertCanMakeWriter()
 {
     if (SerializeColumns.Length == 0)
     {
         Throw.InvalidOperationException($"No columns configured to write for {typeof(T).FullName}");
     }
 }
예제 #5
0
        internal ReaderStateMachine(
            CharacterLookup preAllocLookup,
            char escapeStartChar,
            char escapeChar,
            RowEndings rowEndings,
            ReadHeaders hasHeaders
            )
        {
            RowEndings = rowEndings;
            HasHeaders = hasHeaders;

            switch (HasHeaders)
            {
            case ReadHeaders.Always:
                CurrentState = State.Header_Start;
                break;

            case ReadHeaders.Never:
                CurrentState = State.Record_Start;
                break;

            default:
                Throw.InvalidOperationException($"Unexpected {nameof(ReadHeaders)}: {HasHeaders}");
                break;
            }

            TransitionMatrixHandle = GetTransitionMatrix(RowEndings, escapeStartChar == escapeChar).Pin();
            TransitionMatrix       = (TransitionRule *)TransitionMatrixHandle.Pointer;

            SuppressCharLookupDispose = true;
            (MinimumCharacter, CharLookupOffset, _, _, CharLookup) = preAllocLookup;
        }
예제 #6
0
        /// <summary>
        /// Create a new IBoundConfiguration(T) with the given Options, for
        ///   use with the given type.
        /// </summary>
        public static IBoundConfiguration <TRow> For <TRow>(Options options)
        {
            Utils.CheckArgumentNull(options, nameof(options));

            var forType = typeof(TRow).GetTypeInfo();

            if (forType == Types.Object)
            {
                Throw.InvalidOperationException($"Use {nameof(ForDynamic)} when creating configurations for dynamic types");
            }

            var deserializeMembers = options.TypeDescriber.EnumerateMembersToDeserialize(forType);
            var serializeMembers   = options.TypeDescriber.EnumerateMembersToSerialize(forType);
            var provider           = options.TypeDescriber.GetInstanceProvider(forType);

            ValidateTypeDescription(forType, deserializeMembers, serializeMembers, provider);

            var serializeColumns = CreateSerializeColumns(forType, options, serializeMembers);

            char?escapeStartEnd = options.EscapedValueStartAndEnd;
            var  valueSep       = options.ValueSeparator;

            // this is entirely knowable now, so go ahead and calculate
            //   and save for future use
            var needsEscape = DetermineNeedsEscape(serializeColumns, escapeStartEnd, valueSep);

            return
                (new ConcreteBoundConfiguration <TRow>(
                     provider,
                     deserializeMembers,
                     serializeColumns,
                     needsEscape,
                     options
                     ));
        }
예제 #7
0
        private void AddToPushback(ReadOnlySpan <char> c)
        {
            if (!PushBackOwner.HasValue)
            {
                PushBackOwner.Value = MemoryPool.Rent(BufferSizeHint);
            }

            var pushBackOwnerValue = PushBackOwner.Value;

            if (PushBackLength + c.Length > pushBackOwnerValue.Memory.Length)
            {
                var oldSize = pushBackOwnerValue.Memory.Length;

                var newSize  = (PushBackLength + c.Length) * 2;   // double size, because we're sharing the buffer
                var newOwner = Utils.RentMustIncrease(MemoryPool, newSize, oldSize);
                pushBackOwnerValue.Memory.CopyTo(newOwner.Memory);

                pushBackOwnerValue.Dispose();
                PushBackOwner.Value = pushBackOwnerValue = newOwner;
            }

            if (PushBackLength + c.Length > pushBackOwnerValue.Memory.Length)
            {
                Throw.InvalidOperationException($"Could not allocate large enough buffer to read headers");
            }

            c.CopyTo(PushBack.Span.Slice(PushBackLength));
            PushBackLength += c.Length;
        }
예제 #8
0
        protected internal ReadWithCommentResult <T> HandleAdvanceResult(ReadWithCommentResultType res, bool returnComments, bool ending)
        {
            switch (res)
            {
            case ReadWithCommentResultType.HasComment:
                if (returnComments)
                {
                    var comment = Partial.PendingAsString(Buffer.Buffer);
                    Partial.ClearBuffer();
                    return(new ReadWithCommentResult <T>(comment));
                }
                Partial.ClearBuffer();
                return(ReadWithCommentResult <T> .Empty);

            case ReadWithCommentResultType.HasValue:
                var record = GetValueForReturn();
                return(new ReadWithCommentResult <T>(record));

            case ReadWithCommentResultType.NoValue:
                if (ending)
                {
                    EndedWithoutReturningRow();
                }
                return(ReadWithCommentResult <T> .Empty);

            default:
                Throw.InvalidOperationException($"Unexpected {nameof(ReadWithCommentResultType)}: {res}");
                return(default);
            }
        }
        private static SerializableMember Map(TypeInfo ontoType, SerializableMember member)
        {
            ShouldSerialize?shouldSerializeOnType;

            if (member.ShouldSerialize.HasValue)
            {
                var surrogateShouldSerializeWrapper = member.ShouldSerialize.Value;
                if (surrogateShouldSerializeWrapper.Mode == BackingMode.Method)
                {
                    if (surrogateShouldSerializeWrapper.Takes.HasValue && surrogateShouldSerializeWrapper.IsStatic)
                    {
                        Throw.InvalidOperationException($"Cannot map 'should serialize' {surrogateShouldSerializeWrapper} onto {ontoType}, it takes a parameter");
                    }

                    var surrogateShouldSerialize        = surrogateShouldSerializeWrapper.Method.Value;
                    var surrogateShouldSerializeBinding = GetEquivalentFlagsFor(surrogateShouldSerialize.IsPublic, surrogateShouldSerialize.IsStatic);

                    // intentionally letting this be null
                    var shouldSerializeOnTypeMtd = ontoType.GetMethod(surrogateShouldSerialize.Name, surrogateShouldSerializeBinding);
                    if (shouldSerializeOnTypeMtd == null)
                    {
                        Throw.InvalidOperationException($"No equivalent to {surrogateShouldSerialize} found on {ontoType}");
                    }

                    shouldSerializeOnType = ShouldSerialize.ForMethod(shouldSerializeOnTypeMtd);
                }
                else
                {
                    Throw.InvalidOperationException($"Cannot map 'should serialize' {surrogateShouldSerializeWrapper} onto {ontoType}, 'should serialize' isn't backed by a method");
                    return(default);
예제 #10
0
        // internal for testing purposes
        internal ManualTypeDescriberBuilder WithSerializableMember(TypeInfo?forType, Getter?getter, string?name, Formatter?formatter, ShouldSerialize?shouldSerialize, EmitDefaultValue emitDefault)
        {
            if (forType == null)
            {
                Throw.ArgumentNullException(nameof(forType));
            }

            if (getter == null)
            {
                Throw.ArgumentNullException(nameof(getter));
            }

            if (name == null)
            {
                Throw.ArgumentNullException(nameof(name));
            }

            if (formatter == null)
            {
                Throw.ArgumentNullException(nameof(name));
            }

            // shouldSerialize can be null

            if (getter.RowType.HasValue)
            {
                var      getterOnType = getter.RowType.Value;
                var      isLegal      = false;
                TypeInfo?cur          = forType;

                while (cur != null)
                {
                    if (cur == getterOnType)
                    {
                        isLegal = true;
                        break;
                    }

                    cur = cur?.BaseType?.GetTypeInfo();
                }

                if (!isLegal)
                {
                    Throw.InvalidOperationException($"Provided getter ({getter}) is not on {forType} or one of it's base types.");
                }
            }

            var toAdd = SerializableMember.Create(forType, name, getter, formatter, shouldSerialize, emitDefault);

            if (!Serializers.TryGetValue(forType, out var s))
            {
                Serializers[forType] = s = ImmutableArray.CreateBuilder <SerializableMember>();
            }

            s.Add(toAdd);

            return(this);
        }
예제 #11
0
        internal static object GetValueNonNull(this PropertyInfo prop, object?obj)
        {
            var ret = prop.GetValue(obj);

            if (ret == null)
            {
                Throw.InvalidOperationException($"Expected non-null value when reading property {prop}, but was null");
            }

            return(ret);
        }
예제 #12
0
        internal ReadOnlySpan <char> GetDataSpan()
        {
            var row = SafeRowGet();

            if (!row.TryGetDataSpan(ColumnNumber, out var ret))
            {
                Throw.InvalidOperationException($"{nameof(DynamicCell)} unexpectedly backed by null span");
            }

            return(ret);
        }
예제 #13
0
        public bool TryRead(out T record)
        {
            AssertNotDisposed();

            if (!Configuration.NewCons(out record))
            {
                Throw.InvalidOperationException($"Failed to construct new instance of {typeof(T)}");
            }

            return(TryReadWithReuse(ref record));
        }
예제 #14
0
        internal static object GetValueNonNull(this FieldInfo field, object?obj)
        {
            var ret = field.GetValue(obj);

            if (ret == null)
            {
                Throw.InvalidOperationException($"Expected non-null value when reading field {field}, but was null");
            }

            return(ret);
        }
예제 #15
0
        public bool TryReadWithReuse(ref T record)
        {
            AssertNotDisposed();

            if (RowEndings == null)
            {
                HandleLineEndings();
            }

            if (ReadHeaders == null)
            {
                HandleHeaders();
            }

            while (true)
            {
                PreparingToWriteToBuffer();
                var available = Buffer.Read(Inner);
                if (available == 0)
                {
                    EndOfData();

                    if (HasValueToReturn)
                    {
                        record = GetValueForReturn();
                        return(true);
                    }

                    // intentionally _not_ modifying record here
                    return(false);
                }

                if (!HasValueToReturn)
                {
                    if (record == null)
                    {
                        if (!Configuration.NewCons(out record))
                        {
                            Throw.InvalidOperationException($"Failed to construct new instance of {typeof(T)}");
                        }
                    }
                    SetValueToPopulate(record);
                }

                var res = AdvanceWork(available);
                if (res)
                {
                    record = GetValueForReturn();
                    return(true);
                }
            }
        }
예제 #16
0
        public InstanceProvider?GetInstanceProvider(TypeInfo forType)
        {
            if (!Builders.TryGetValue(forType, out var ret))
            {
                if (ThrowsOnNoConfiguredType)
                {
                    Throw.InvalidOperationException($"No configured instance provider for {forType}");
                }

                return(Fallback.GetInstanceProvider(forType));
            }

            return(ret);
        }
예제 #17
0
        public override IAsyncWriter <T> CreateAsyncWriter(TextWriter inner, object context = null)
        {
            if (SerializeColumns.Length == 0)
            {
                Throw.InvalidOperationException($"No columns configured to write for {typeof(T).FullName}");
            }

            if (inner == null)
            {
                Throw.ArgumentNullException(nameof(inner));
            }

            return(new AsyncWriter <T>(this, inner, context));
        }
예제 #18
0
        internal static SerializableMember CreateInner(TypeInfo?beingSerializedType, string?name, Getter?getter, Formatter?formatter, ShouldSerialize?shouldSerialize, EmitDefaultValue emitDefault)
        {
            if (beingSerializedType == null)
            {
                Throw.ArgumentNullException(nameof(beingSerializedType));
            }

            if (name == null)
            {
                Throw.ArgumentNullException(nameof(name));
            }

            if (getter == null)
            {
                Throw.ArgumentNullException(nameof(getter));
            }

            if (formatter == null)
            {
                Throw.ArgumentNullException(nameof(formatter));
            }

            bool emitDefaultValueBool;

            switch (emitDefault)
            {
            case Cesil.EmitDefaultValue.Yes:
                emitDefaultValueBool = true;
                break;

            case Cesil.EmitDefaultValue.No:
                emitDefaultValueBool = false;
                break;

            default:
                Throw.InvalidOperationException($"Unexpected {nameof(Cesil.EmitDefaultValue)}: {emitDefault}");
                return(default);
            }

            var toSerializeType = getter.Returns;

            if (!formatter.Takes.IsAssignableFrom(toSerializeType))
            {
                Throw.ArgumentException($"The first parameter to {nameof(formatter)} must accept a {toSerializeType}", nameof(formatter));
            }

            CheckShouldSerializeMethod(shouldSerialize, getter.RowType);

            return(new SerializableMember(name, getter, formatter, shouldSerialize, emitDefaultValueBool));
        }
예제 #19
0
        // internal for testing purposes
        internal static NameLookup CreateInner(OrdererNames ordered, MemoryPool <char> memoryPool)
        {
            if (TryCreateAdaptiveRadixTrie(ordered, memoryPool, out var trieOwner, out var trieMem))
            {
                return(new NameLookup(Algorithm.AdaptiveRadixTrie, trieOwner, trieMem));
            }

            if (TryCreateBinarySearch(ordered, memoryPool, out var binaryTreeOwner, out var binaryTreeMem))
            {
                return(new NameLookup(Algorithm.BinarySearch, binaryTreeOwner, binaryTreeMem));
            }

            Throw.InvalidOperationException($"Could create a lookup for dynamic member names, names could not fit in memory acquired from MemoryPool: {memoryPool}");
            return(default);
예제 #20
0
        /// <summary>
        /// Enumerate all the members on forType to deserialize.
        ///
        /// If no members has been registered, will either delegate to a fallback
        ///    ITypeProvider or throw an exception depending on configuration.
        /// </summary>
        public IEnumerable <DeserializableMember> EnumerateMembersToDeserialize(TypeInfo forType)
        {
            if (!Deserializers.TryGetValue(forType, out var ret))
            {
                if (ThrowsOnNoConfiguredType)
                {
                    Throw.InvalidOperationException($"No configured members to deserialize for {forType}");
                }

                return(Fallback.EnumerateMembersToDeserialize(forType));
            }

            return(ret);
        }
예제 #21
0
        public override IReader <T> CreateReader(TextReader inner, object context = null)
        {
            if (DeserializeColumns.Length == 0)
            {
                Throw.InvalidOperationException($"No columns configured to read for {typeof(T).FullName}");
            }

            if (inner == null)
            {
                Throw.ArgumentNullException(nameof(inner));
            }

            return(new Reader <T>(inner, this, context));
        }
예제 #22
0
        internal void Init(IDynamicRowOwner owner, int rowNumber, int width, IDynamicTypeConverter converter, string[] names, MemoryPool <char> pool)
        {
            if (!IsDisposed)
            {
                Throw.InvalidOperationException("DynamicRow not in an uninitializable state");
            }

            Owner      = owner;
            RowNumber  = rowNumber;
            Converter  = converter;
            MemoryPool = pool;
            Width      = width;
            Names      = names;
            Generation++;
        }
예제 #23
0
        /// <summary>
        /// Gets an instance builder usable to construct the given type.
        ///
        /// If a surrogate is registered, the surrogate will be used for discovery - the returned
        ///   constructor will be mapped from the surrogate to forType.
        ///
        /// If a surrogate is not registered, either an exception will be thrown or forType will
        ///   be passed to TypeDescriber.GetInstanceBuilder depending on the value of
        ///   ThrowOnNoRegisteredSurrogate.
        /// </summary>
        public InstanceBuilder GetInstanceBuilder(TypeInfo forType)
        {
            if (!SurrogateTypes.TryGetValue(forType, out var proxy))
            {
                if (ThrowOnNoRegisteredSurrogate)
                {
                    Throw.InvalidOperationException($"No surrogate registered for {forType}");
                }

                return(TypeDescriber.GetInstanceBuilder(forType));
            }

            var fromProxy = TypeDescriber.GetInstanceBuilder(forType);

            return(Map(forType, fromProxy));
        }
예제 #24
0
        internal void GetDataSpanAndReadContext(out ReadOnlySpan <char> data, out ReadContext ctx)
        {
            var r = SafeRowGet();

            if (!r.TryGetDataSpan(ColumnNumber, out data))
            {
                data = default;
                ctx  = default;
                Throw.InvalidOperationException($"{nameof(DynamicCell)} unexpectedly backed by null span");
            }

            var name = r.Columns[ColumnNumber];

            var owner = r.Owner;

            ctx = ReadContext.ReadingColumn(owner.Options, r.RowNumber, name, owner.Context);
        }
예제 #25
0
        internal unsafe void Initialize(
            CharacterLookup preAllocLookup,
            char?escapeStartChar,
            char?escapeChar,
            ReadRowEnding rowEndings,
            ReadHeader hasHeaders,
            bool readingComments,
            bool skipLeadingWhitespace,
            bool skipTrailingWhitespace
            )
        {
            CharacterLookup = preAllocLookup;
            CharLookup      = (CharacterType *)preAllocLookup.Memory;
            RowEndings      = rowEndings;
            HasHeaders      = hasHeaders;

            switch (HasHeaders)
            {
            case ReadHeader.Always:
                CurrentState = State.Header_Start;
                break;

            case ReadHeader.Never:
                CurrentState = State.Record_Start;
                break;

            default:
                Throw.InvalidOperationException($"Unexpected {nameof(ReadHeader)}: {HasHeaders}");
                break;
            }

            TransitionMatrix =
                GetTransitionMatrix(
                    RowEndings,
                    escapeStartChar.HasValue && escapeStartChar == escapeChar,
                    readingComments,
                    skipLeadingWhitespace,
                    skipTrailingWhitespace,
#if DEBUG
                    out TransitionMatrixMemoryOffset
#else
                    out _
#endif
                    );
        }
예제 #26
0
        public override void WriteComment(ReadOnlySpan <char> comment)
        {
            AssertNotDisposed(this);
            AssertNotPoisoned(Configuration);

            try
            {
                WriteHeadersAndEndRowIfNeeded();

                var options             = Configuration.Options;
                var commentCharNullable = options.CommentCharacter;

                if (commentCharNullable == null)
                {
                    Throw.InvalidOperationException($"No {nameof(Options.CommentCharacter)} configured, cannot write a comment line");
                }

                var commentChar   = commentCharNullable.Value;
                var rowEndingSpan = Configuration.RowEndingMemory.Span;

                var splitIx = Utils.FindNextIx(0, comment, rowEndingSpan);
                if (splitIx == -1)
                {
                    // single segment
                    PlaceCharInStaging(commentChar);
                    if (comment.Length > 0)
                    {
                        PlaceAllInStaging(comment);
                    }
                }
                else
                {
                    // multi segment
                    var prevIx = 0;

                    var isFirstRow = true;
                    while (splitIx != -1)
                    {
                        if (!isFirstRow)
                        {
                            EndRecord();
                        }

                        PlaceCharInStaging(commentChar);
                        var segSpan = comment[prevIx..splitIx];
        /// <summary>
        /// Registered a surrogate type for forType.
        ///
        /// Whenever forType is passed to one of the EnumerateXXX methods, surrogateType
        ///   will be used to discover members instead.  The discovered members will then
        ///   be mapped to forType, and returned.
        /// </summary>
        public SurrogateTypeDescriberBuilder WithSurrogateType(TypeInfo forType, TypeInfo surrogateType)
        {
            Utils.CheckArgumentNull(forType, nameof(forType));
            Utils.CheckArgumentNull(surrogateType, nameof(surrogateType));

            if (forType == surrogateType)
            {
                Throw.InvalidOperationException($"Type {forType} cannot be a surrogate for itself");
            }

            if (SurrogateTypes.ContainsKey(forType))
            {
                Throw.InvalidOperationException($"Surrogate already registered for {forType}");
            }

            SurrogateTypes[forType] = surrogateType;

            return(this);
        }
예제 #28
0
        private void HandleHeaders()
        {
            ReadHeaders = Configuration.ReadHeader;
            TryMakeStateMachine();

            var allowColumnsByName = Configuration.ReadHeader == Cesil.ReadHeaders.Always;

            using (var reader = new HeadersReader <object>(Configuration, SharedCharacterLookup, Inner, Buffer))
            {
                var res          = reader.Read();
                var foundHeaders = res.Headers.Count;
                if (foundHeaders == 0)
                {
                    Throw.InvalidOperationException("Expected a header row, but found no headers");
                }

                Columns = new Column[foundHeaders];
                if (allowColumnsByName)
                {
                    ColumnNames = new string[foundHeaders];
                }

                using (var e = res.Headers)
                {
                    var ix = 0;
                    while (e.MoveNext())
                    {
                        var name = allowColumnsByName ? new string(e.Current.Span) : null;
                        if (name != null)
                        {
                            ColumnNames[ix] = name;
                        }
                        var col = new Column(name, Column.MakeDynamicSetter(name, ix), null, false);
                        Columns[ix] = col;

                        ix++;
                    }
                }

                Buffer.PushBackFromOutsideBuffer(res.PushBack);
            }
        }
예제 #29
0
        internal static IMemoryOwner <T> RentMustIncrease <T>(MemoryPool <T> pool, int newSize, int oldSize)
        {
            int requestSize;

            if (newSize > pool.MaxBufferSize)
            {
                if (oldSize >= pool.MaxBufferSize)
                {
                    Throw.InvalidOperationException($"Needed a larger memory segment than could be requested, needed {newSize:N0}; {nameof(MemoryPool<T>.MaxBufferSize)} = {pool.MaxBufferSize:N0}");
                }

                requestSize = pool.MaxBufferSize;
            }
            else
            {
                requestSize = newSize;
            }

            return(pool.Rent(requestSize));
        }
예제 #30
0
        internal void AssertNotPoisoned <T>(IBoundConfiguration <T> self)
        {
            if (Poison != null)
            {
                switch (Poison.Value)
                {
                case PoisonType.Cancelled:
                    Throw.InvalidOperationException("Object is in an invalid state, a previous operation was canceled");
                    return;

                case PoisonType.Exception:
                    Throw.InvalidOperationException("Object is in an invalid state, a previous operation raised an exception");
                    return;

                default:
                    Throw.ImpossibleException($"Unexpected {nameof(PoisonType)}: {Poison}", self);
                    return;
                }
            }
        }