diff --git a/content.go b/content.go new file mode 100644 index 0000000..e665284 --- /dev/null +++ b/content.go @@ -0,0 +1,152 @@ +package strfs + +import ( + "io" + "strings" +) + +// Content represents the content part of a file. +// +// Content does NOT map to anything in Go's built-in "fs" package. +// +// But, for example, is used to create a RegularFile (which maps to a fs.File). +// +// Example usage: +// +// var content strfs.Content = strfs.CreateContent(""+"\n"+"") +// +// var regularfile strfs.RegularFile = strfs.RegularFile{ +// FileContent: content, +// FileName: "notice.html", +// FileModTIme: time.Date(2022, 12, 12, 10, 30, 14, 2, time.UTC), +// } +type Content struct{ + reader io.Reader + size int64 + closed bool +} + +// A trick to make sure strfs.Content fits the io.ReadCloser interface. +// This is a compile-time check. +var _ io.ReadCloser = &Content{} + +// CreateContent returns a strfs.Content whose content is the string given to it. +// +// Example usage: +// +// var content strfs.Content = strfs.CreateContent("# Hello world!"+"\r\r"+"Welcome to my document."+"\n") +// +// var regularfile strfs.RegularFile = strfs.RegularFile{ +// FileContent: content, +// FileName: "message.md", +// FileModTIme: time.Now(), +// } +func CreateContent(s string) Content { + var reader io.Reader = strings.NewReader(s) + var size int64 = int64(len(s)) + + return Content{ + reader:reader, + size:size, + } +} + +// NoContent is used to see if a given strfs.Content has no content. +// +// Note that having no content is NOT the same as containing the empty string! +// +// A strfs.Content contains no content when it hasn't been initialized. +// +// Example usage: +// +// var content strfs.Content +// +// // ... +// +// if strfs.NoContent() == content { +// //@TODO +// } +func NoContent() Content { + return Content{} +} + +// Close makes strfs.Content fit the io.Closer interface. +// +// Call close will stop the Read method from working. +// +// Close can safely be called more than once. +func (receiver *Content) Close() error { + if nil == receiver { + return errNilReceiver + } + + if receiver.closed { + return nil + } + + receiver.closed = true + return nil +} + +// Closed returns whether a strfs.Content is closed or not. +func (receiver *Content) Closed() bool { + if nil == receiver { + return true + } + + return receiver.closed +} +// Read makes strfs.Content fit the io.Reader interface. +// +// Read reads up to len(p) bytes into 'p'. +// Read returns the number of bytes actually read, and any errors it encountered. +// +// Example usage: +// +// var content strfs.Content = strfs.CreateContent("ABCDEFGHIJKLMNOPQRSTUVWXYZ") +// +// var b1 [5]byte +// var p1 []byte = b1[:] +// +// n, err := content.Read(p1) +// +// // n == 5 +// // b1 == [5]byte{'A', 'B', 'C', 'D', 'E'} +// +// // ... +// +// var b2 [4]byte +// var p2 []byte = b2[:] +// +// n, err := content.Read(p2) +// +// // n == 4 +// // b2 == [5]byte{'F', 'G', 'H', 'I'} +func (receiver *Content) Read(p []byte) (int, error) { + if nil == receiver { + return 0, errNilReceiver + } + if nil == p { + return 0, errNilByteSlice + } + + var reader io.Reader = receiver.reader + if nil == reader { + return 0, errInternalError + } + + if receiver.closed { + return 0, nil + } + + return receiver.reader.Read(p) +} + +// Size returns the of the strnig given to it as the number of bytes. +func (receiver *Content) Size() int64 { + if nil == receiver { + return 0 + } + + return receiver.size +}