Spinner is a simple object mapper, it’s useful to communicate to any system that uses a positional string as communication.
$ dotnet add package SpinnerDocumentation | |
</div> <div align="center"> </div>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.
| 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:
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
We welcome contributions from the community! Here's how you can help:
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:
feature/add-new-padding-mode or fix/null-reference-bug)Fixes #123 or Closes #456dotnet test passesUse 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)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.mdSpinner follows Semantic Versioning:
Planned features for future releases:
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!
If you find Spinner useful, consider:
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.
Made with ❤️ by the Daniel-Iel