This repository has been archived on 2023-02-02. You can view files and clone it, but cannot push or open issues or pull requests.
mfgames-nitride-cil/src/MfGames.Nitride/Contents/README.md

187 lines
5.1 KiB
Markdown
Raw Normal View History

2021-09-07 05:15:45 +00:00
# Contents
The contents of a file may be stored as a component, however this increases the
memory pressure when Nitride works with hundreds or thousands of files. To
reduce this, memory is loaded on demand through an abstracted components such
as `IBinaryContent` and `ITextContent`.
## Exclusivity
The content interfaces are treated as _mutually exclusive_ with each other by
2021-09-07 05:15:45 +00:00
extending the `IContent` interface. The intended reason for this is to have a
single source of data that doesn't go out of sync. Adding or setting
a `IBinaryContent` will remove the other content components in the entity, even
ones that are defined in other classes. In effect, all `IContent`
will be removed to ensure that. This is implemented via a number of extension
operations.
```c#
Entity entity;
IBinaryContent binaryContent;
ITextContent textContent;
entity.Add(binaryContent);
Assert.Equal(1, entity.Count);
Assert.True(entity.Has<IBinaryContent>());
Assert.True(entity.HasBinaryContent());
Assert.True(entity.HasContent());
entity.SetContent(textContent);
Assert.Equal(1, entity.Count);
Assert.False(entity.Has<IBinaryContent>());
Assert.False(entity.HasBinaryContent());
Assert.True(entity.Has<ITextContent>());
Assert.True(entity.HasTextContent());
Assert.True(entity.HasContent());
entity.RemoveContent();
Assert.Equal(0, entity.Count);
Assert.False(entity.Has<IBinaryContent>());
Assert.False(entity.HasBinaryContent());
Assert.False(entity.Has<ITextContent>());
Assert.False(entity.HasTextContent());
Assert.False(entity.HasContent());
```
This exclusivity can be ignored by using direct `Add<>`, `Set<>`, and
`Remove<>` methods on the entity. That would allow multiple content to be added
and removed at the same time.
```c#
Entity entity;
IBinaryContent binaryContent = entity.Get<IBinaryContent>();
using Stream binaryStream = binaryContent.GetStream();
using StreamReader binaryReader = new StreamReader(binaryStream);
var text = binaryReader.ReadToEnd();
var textContent = new StringTextContent(text);
var switchedEntity = entity
.Set<ITextContent>(textContent)
.Remove<IBinaryContent>();
Assert.Equal(1, switchedEntity.Count);
Assert.True(switchedEntity.Has<ITextContent>());
Assert.False(switchedEntity.Has<ITextContent>());
var mergedEntity = entity
.Set<ITextContent>(textContent);
Assert.Equal(2, switchedEntity.Count);
Assert.True(switchedEntity.Has<ITextContent>());
Assert.True(switchedEntity.Has<ITextContent>());
```
Implementing this with a parent interface (`IContent`) allows future content
providers, such as `IXmlContent` or other future content sources.
## IBinaryComponent
Most files start as only having access to binary content.
```c#
Entity entity;
IBinaryContent content = entity.Get<IBinaryContent>();
using Stream stream = content.GetStream();
```
There is no guarantee that the data behind the stream is loaded into memory or
even available on disk. Instead, the stream is good until it goes out of scope.
### IBinaryContentConvertable
There is an additional interface that allows a content to be converted into
an `IBinaryContent).`
```c#
FileTextContent textContent;
IBinaryContent binaryContent = textContent.ToBinaryContent();
```
### Extension Methods
There are some convenience methods for working with entity components and
content since they are frequently used.
```c#
IBinaryContent content = entity.GetBinaryContent();
bool has = entity.HasBinaryContent();
// Internally, this uses `SetContent` above with some additonal type safety.
entity = entity.SetBinaryContent(content);
```
### ByteArrayBinaryComponent
The `ByteArrayBinaryComponent` is a component that contains the entire binary
data in memory and returns it via `System.IO.MemoryStream` objects.
```c#
byte[] bytes;
var content = new ByteArrayBinaryComponent(bytes);
```
### FileBinaryContent
The `TextBinaryContent` takes a path or FileInfo object as the parameter and
will produce a stream directly from the file without loading the file into
memory.
```c#
FileInfo file;
new FileBinaryContent(@"C:\Temp\Bob.txt");
new FileBinaryContent(file);
```
## ITextContent
Text content allows for retrieving the contents via `TextReader` instead of a
2021-09-07 05:15:45 +00:00
stream.
```c#
ITextContent content;
using TextReader reader = content.GetReader();
```
### ITextContentConvertable
There is an additional interface that allows a content to be converted into
an `ITextContent).`
```c#
FileBinaryContent binaryContent;
ITextContent textContent = binaryContent.ToTextContent();
```
### Extension Methods
Like the binary, there are some convenience methods for working with entity
components.
```c#
ITextContent content = entity.GetTextContent();
bool has = entity.HasTextContent();
entity = entity.SetTextContent(content);
```
### StringTextContent
A simple, in-memory string text content takes a string as the parameter.
```c#
string input;
ITextContent content = new StringTextContent(input);
```
### FileTextContent
The `TextFileContent` takes a path or FileInfo object as the parameter and will
produce a reader directly from the file without loading the file into memory.
```c#
FileInfo file;
new FileTextContent(@"C:\Temp\Bob.txt");
new FileTextContent(file);
```