Spinner is a high-performance .NET library for converting objects to and from positional (fixed-width) strings. Designed for scenarios where you need to work with legacy file formats, mainframe data, or any system that uses fixed-position text records.
- β‘ Blazing Fast - Up to 79x faster than previous versions
- πΎ Memory Efficient - Up to 26x less memory allocation
- π― Type-Safe - Compile-time validation with attributes
- π§ Easy to Use - Simple, intuitive API
- π§ͺ Battle-Tested - High test coverage with mutation testing
- π¦ Zero Dependencies - Lightweight and self-contained
- ? Blazing Fast Performance - Up to 79x faster than v1.x with optimized compiled delegates
- ?? Memory Efficient - Up to 26x less memory allocation with ThreadStatic StringBuilder
- ?? High-Throughput Ready - Process millions of records in milliseconds
- ?? Zero-Allocation Scenarios - Near-zero allocation with Span-based operations
- ?? Seamless Conversions - Effortlessly transform objects to/from positional strings
- ?? Type-Safe Parsing - Built-in support for 18+ primitive types (int, decimal, DateTime, etc.)
- ?? Configurable Padding - Left/Right padding with custom characters
- ?? Custom Interceptors - Extensible value transformation pipeline
| Operation | v1.x | v2.0 | Improvement |
|---|---|---|---|
| ReadFromString | 2.8 οΏ½s | 46 ns | 60x faster ? |
| WriteAsString | 1.2 οΏ½s | 40 ns | 31x faster ? |
| Memory Usage | 664-808 B | 32-128 B | 6-20x less ?? |
Benchmarks run on .NET 10.0 with BenchmarkDotNet. See detailed benchmarks for more information.
Spinner is perfect for:
- Legacy System Integration - Parse and generate mainframe-style fixed-width files
- EDI Processing - Handle Electronic Data Interchange formats
- Banking & Finance - Process CNAB, FEBRABAN, and other financial formats
- Government Systems - Work with standardized fixed-position government data
- Data Migration - Convert between legacy and modern data formats
- Report Generation - Create fixed-width reports for legacy systems
Install via NuGet Package Manager:
dotnet add package SpinnerOr via Package Manager Console:
Install-Package SpinnerTransform objects into positional strings:
[ObjectMapper(length: 50)]
public struct Nothing
{
public Nothing(string name, string webSite)
{
this.Name = name;
this.WebSite = webSite;
}
[WriteProperty(length: 20, order: 1, paddingChar: ' ')]
public string Name { get; private set; }
[WriteProperty(length: 30, order: 2, paddingChar: ' ')]
public string WebSite { get; private set; }
}
var nothing = new Nothing("spinner", "www.spinner.com.br");
var spinner = new Spinner<Nothing>();
var stringResponse = spinner.WriteAsString(nothing);
// Output: " spinner www.spinner.com.br"Parse positional strings into objects:
[ObjectMapper(length: 50)]
public class NothingReader
{
[ReadProperty(start: 0, length: 20)]
public string Name { get; set; }
[ReadProperty(start: 20, length: 30)]
public string WebSite { get; set; }
}
var spinner = new Spinner<NothingReader>();
var obj = spinner.ReadFromString(" spinner www.spinner.com.br");
// obj.Name = "spinner"
// obj.WebSite = "www.spinner.com.br"// Use Span for better performance
ReadOnlySpan<char> data = input.AsSpan();
var obj = spinner.ReadFromSpan(data);
// Custom padding
[WriteProperty(length: 10, order: 1, paddingChar: '0', padding: PaddingType.Left)]
public string Code { get; set; } // "123" β "0000000123"
// Automatic type conversion
[ReadProperty(start: 0, length: 10)]
public int Age { get; set; } // Automatically parses string to int
[ReadProperty(start: 10, length: 20)]
public DateTime BirthDate { get; set; } // Automatically parses to DateTimeFor more examples, see the full documentation.
For comprehensive documentation, visit our official website: spinnerframework.com
- Getting Started - Installation and basic usage
- Writing Objects - Convert objects to positional strings
- Reading Strings - Parse positional strings to objects
- Interceptors - Custom value transformations
- Advanced Features - Thread-safety, padding, and optimizations
- Migration Guide - Upgrading from v1.x to v2.0
- Performance Benchmarks - Detailed performance analysis
We welcome contributions from the community! Here's how you can help:
- π Report Bugs - Found an issue? Open a bug report
- β¨ Suggest Features - Have an idea? Request a feature
- π Improve Documentation - Help make our docs better
- π» Submit Code - Fix bugs or implement new features
- β Star the Repo - Show your support!
-
Fork and Clone
git clone https://github.com/YOUR-USERNAME/Spinner.git cd Spinner -
Build the Project
cd src dotnet build -
Run Tests
cd Spinner.Test dotnet test
-
Run Benchmarks (optional)
cd bench/Spinner.Benchmark dotnet run -c Release
When submitting a PR, please follow these guidelines:
- β Create an Issue First - Discuss your proposal before starting work
- β Fork the Repository - Work on your own fork
- β
Create a Feature Branch - Use descriptive names (e.g.,
feature/add-new-padding-modeorfix/null-reference-bug) - β Follow Code Style - Match the existing code style and conventions
- β Write Tests - Add or update tests for your changes
- β Update Documentation - If you change functionality, update the docs
- π Clear Description - Explain what changes you made and why
- π Link Related Issues - Reference issues using
Fixes #123orCloses #456 - β
All Tests Pass - Ensure
dotnet testpasses - π No Performance Regression - Run benchmarks for performance-critical changes
- π Documentation Updated - Update README.md or docs/ if needed
- π Code Review Ready - Address all review comments promptly
Use conventional commits format:
feat: Add support for custom date formats
fix: Resolve null reference in ReadFromSpan
docs: Update migration guide with examples
perf: Optimize StringBuilder allocation
test: Add unit tests for padding scenarios
refactor: Simplify property cache initialization
## Description
This PR adds support for custom date format parsing using interceptors.
## Changes
- Added `DateFormatInterceptor` example to documentation
- Updated `mapping-string-into-type.md` with date parsing examples
- Added unit tests for date format validation
## Related Issues
Fixes #42
## Testing
- [x] All existing tests pass
- [x] Added new tests for date format parsing
- [x] Manually tested with multiple date formats
## Checklist
- [x] Code follows project style guidelines
- [x] Tests added/updated
- [x] Documentation updated
- [x] No breaking changes (or documented if breaking)- C# Version: Target .NET 5+
- Code Style: Follow standard C# conventions
- Naming: Use PascalCase for public members, camelCase for private
- Performance: Consider memory allocations and performance impact
- Thread Safety: Ensure code is thread-safe where applicable
- Tests: Aim for high code coverage with meaningful tests
We use Stryker.NET for mutation testing:
cd src/Spinner.Test
dotnet strykerSpinner/
βββ src/
β βββ Spinner/ # Main library
β βββ Spinner.Test/ # Unit tests
βββ bench/
β βββ Spinner.Benchmark/ # Performance benchmarks
βββ docs/ # Documentation (Docusaurus)
βββ README.md
- π¬ Discussions - GitHub Discussions
- π Issues - GitHub Issues
- π§ Contact - For security issues, contact the maintainers privately
Spinner follows Semantic Versioning:
- Major version (X.0.0) - Breaking changes
- Minor version (0.X.0) - New features, backward compatible
- Patch version (0.0.X) - Bug fixes, backward compatible
- .NET 10.0
- .NET 09.0
- .NET 08.0
Planned features for future releases:
- Source Generators for compile-time validation
- Support for nested objects
- Custom encoding support (EBCDIC, ASCII variants)
- Async read/write operations for streams
- Record type support
- Enhanced error messages with detailed diagnostics
See our GitHub Issues for the full list of planned features and vote on what you'd like to see next!
A huge thank you to all our contributors! π
Want to see your name here? Check out our Contributing Guide and submit a PR!
- BenchmarkDotNet - For excellent benchmarking tools
- Stryker.NET - For mutation testing capabilities
- All contributors - For making this project better
If you find Spinner useful, consider:
- β Star this repository - Help others discover the project
- π’ Share with colleagues - Spread the word
- π° Sponsor the project - Help maintain infrastructure (domain, SSL, CI/CD)
- π Report issues - Help us improve quality
- π» Contribute code - Make Spinner even better
Your support helps keep Spinner maintained and improved. All donations are used exclusively for project infrastructure (domain, SSL certificates, and CI/CD resources).
Spinner is licensed under the MIT License.
Copyright (c) 2025 Daniel-iel
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
TL;DR - You can do whatever you want with this code as long as you include the original copyright and license notice.

