Page Menu
Home
Phorge
Search
Configure Global Search
Log In
Files
F2578199
file-desc.hpp
No One
Temporary
Actions
Download File
Edit File
Delete File
View Transforms
Subscribe
Award Token
Flag For Later
Size
10 KB
Referenced Files
None
Subscribers
None
file-desc.hpp
View Options
/*
* Copyright (C) 2021 Tusooa Zhu <tusooa@vista.aero>
*
* This file is part of libkazv.
*
* libkazv is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* libkazv is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with libkazv. If not, see <https://www.gnu.org/licenses/>.
*/
#pragma once
#include
"libkazv-config.hpp"
#include
<string>
#include
<variant>
#include
<immer/box.hpp>
#include
<immer/flex_vector.hpp>
namespace
Kazv
{
enum
struct
FileOpRetCode
{
Error
,
Success
,
Eof
};
enum
struct
FileOpenMode
{
Read
,
Write
};
using
FileContent
=
immer
::
flex_vector
<
char
>
;
class
FileStream
{
public
:
using
DataT
=
FileContent
;
/**
* Constructor.
*
* Construct a FileStream using `o`.
*
* `o` should be of a type that accepts the `read` and
* `write` methods in this class. That is,
* `o.read(int{}, std::function<void(FileOpRetCode, DataT)>{})`
* and `o.write(DataT{}, std::function<void(FileOpRetCode, int)>{})`
* must both be well-formed.
*/
template
<
class
DeriveT
>
FileStream
(
DeriveT
&&
o
)
:
m_d
(
std
::
make_unique
<
Model
<
std
::
decay_t
<
DeriveT
>>>
(
std
::
forward
<
DeriveT
>
(
o
)))
{}
/**
* Read at most maxSize bytes from the stream.
*
* This calls `readCallback(FileOpRetCode::Success, data)` upon success,
* where `data` is a DataT containing the bytes read;
* calls `readCallback(FileOpRetCode::Eof, DataT{})` upon meeting EOF;
* and calls `readCallback(FileOpRetCode::Error, DataT{})` upon other errors.
*/
template
<
class
Callback
>
void
read
(
int
maxSize
,
Callback
readCallback
)
{
m_d
->
read
(
maxSize
,
readCallback
);
}
/**
* Write `data` into the stream.
*
* This calls `writeCallback(FileOpRetCode::Success, num)` upon success,
* where `num` is an integer that contains the number of bytes written.
* and calls `readCallback(FileOpRetCode::Error, 0)` upon other errors.
*/
template
<
class
Callback
>
void
write
(
DataT
data
,
Callback
writeCallback
)
{
m_d
->
write
(
data
,
writeCallback
);
}
private
:
struct
Concept
{
virtual
~
Concept
()
=
default
;
using
ReadCallback
=
std
::
function
<
void
(
FileOpRetCode
,
DataT
)
>
;
using
WriteCallback
=
std
::
function
<
void
(
FileOpRetCode
,
int
)
>
;
virtual
void
read
(
int
maxSize
,
ReadCallback
callback
)
=
0
;
virtual
void
write
(
DataT
data
,
WriteCallback
callback
)
=
0
;
};
template
<
class
DeriveT
>
struct
Model
:
public
Concept
{
explicit
Model
(
const
DeriveT
&
o
)
:
obj
(
o
)
{}
explicit
Model
(
DeriveT
&&
o
)
:
obj
(
std
::
move
(
o
))
{}
~
Model
()
override
=
default
;
void
read
(
int
maxSize
,
ReadCallback
callback
)
override
{
return
obj
.
read
(
maxSize
,
callback
);
}
void
write
(
DataT
data
,
WriteCallback
callback
)
override
{
return
obj
.
write
(
data
,
callback
);
}
DeriveT
obj
;
};
std
::
unique_ptr
<
Concept
>
m_d
;
};
class
FileProvider
{
public
:
/**
* Constructor.
*
* Construct a FileProvider using `o`.
*
* `o` should be of a copyable type `T` that has a method
* `getStream()` that takes a FileOpenMode
* and returns something implicitly convertible
* to FileStream.
*
* That is, `[o]() -> FileStream { return o.getStream(FileOpenMode::Read); }`
* must be well-formed.
*
* In addition, if the FileOpenMode passed to getStream is FileOpenMode::Read,
* the returned stream must support read(); if the FileOpenMode passed to getStream
* is FileOpenMode::Write, the returned stream must support write().
*/
template
<
class
DeriveT
>
FileProvider
(
DeriveT
&&
o
)
:
m_d
(
std
::
make_unique
<
Model
<
std
::
decay_t
<
DeriveT
>>>
(
std
::
forward
<
DeriveT
>
(
o
)))
{}
inline
FileProvider
(
const
FileProvider
&
that
)
:
m_d
(
that
.
m_d
->
clone
())
{}
inline
FileProvider
(
FileProvider
&&
that
)
:
m_d
(
std
::
move
(
that
.
m_d
))
{}
inline
FileProvider
&
operator
=
(
const
FileProvider
&
that
)
{
m_d
=
that
.
m_d
->
clone
();
return
*
this
;
}
inline
FileProvider
&
operator
=
(
FileProvider
&&
that
)
{
m_d
=
std
::
move
(
that
.
m_d
);
return
*
this
;
}
/**
* Get the file stream provided by this.
*
* @return a FileStream that will contain the content
* of the file provided by this.
*/
inline
FileStream
getStream
(
FileOpenMode
mode
=
FileOpenMode
::
Read
)
const
{
return
m_d
->
getStream
(
mode
);
}
private
:
struct
Concept
{
virtual
~
Concept
()
=
default
;
virtual
std
::
unique_ptr
<
Concept
>
clone
()
const
=
0
;
virtual
FileStream
getStream
(
FileOpenMode
mode
)
const
=
0
;
};
template
<
class
DeriveT
>
struct
Model
:
public
Concept
{
explicit
Model
(
const
DeriveT
&
o
)
:
obj
(
o
)
{}
explicit
Model
(
DeriveT
&&
o
)
:
obj
(
std
::
move
(
o
))
{}
~
Model
()
override
=
default
;
std
::
unique_ptr
<
Concept
>
clone
()
const
override
{
return
std
::
make_unique
<
Model
>
(
obj
);
}
FileStream
getStream
(
FileOpenMode
mode
)
const
override
{
return
obj
.
getStream
(
mode
);
}
DeriveT
obj
;
};
std
::
unique_ptr
<
Concept
>
m_d
;
};
class
FileDesc
;
class
FileInterface
;
struct
DumbFileStream
{
inline
explicit
DumbFileStream
(
FileContent
r
)
:
remaining
(
r
)
{}
template
<
class
Callback
>
void
read
(
int
maxSize
,
Callback
callback
)
{
if
(
remaining
.
empty
())
{
callback
(
FileOpRetCode
::
Eof
,
remaining
);
}
else
{
auto
taken
=
remaining
.
take
(
maxSize
);
remaining
=
remaining
.
drop
(
maxSize
);
callback
(
FileOpRetCode
::
Success
,
taken
);
}
}
template
<
class
Callback
>
void
write
(
FileContent
data
,
Callback
callback
)
{
remaining
=
remaining
+
data
;
callback
(
FileOpRetCode
::
Success
,
data
.
size
());
}
FileContent
remaining
;
};
struct
DumbFileProvider
{
inline
explicit
DumbFileProvider
(
FileContent
content
)
:
m_content
(
content
)
{}
inline
DumbFileStream
getStream
(
FileOpenMode
/* mode */
)
const
{
return
DumbFileStream
(
m_content
);
}
FileContent
m_content
;
};
class
FileDesc
{
public
:
/**
* Construct an in-memory FileDesc with @c content.
*/
explicit
FileDesc
(
FileContent
content
)
:
m_inMemory
{
true
}
,
m_content
(
content
)
{}
/**
* Construct a FileDesc with @c name and @c contentType.
*/
explicit
FileDesc
(
std
::
string
name
,
std
::
optional
<
std
::
string
>
contentType
=
std
::
nullopt
)
:
m_inMemory
{
false
}
,
m_name
(
std
::
move
(
name
))
,
m_contentType
(
std
::
move
(
contentType
))
{}
/**
* Get the FileProvider for this FileDesc using FileInterface.
*
* If this is an in-memory file, this will always return a
* DumbFileProvider. Otherwise, it will return what
* `fh.getProviderFor(*this)` returns.
*
* @return a FileProvider for this.
*/
FileProvider
provider
(
const
FileInterface
&
fh
)
const
;
/**
* Get the name for this FileDesc.
*/
inline
std
::
optional
<
std
::
string
>
name
()
const
{
return
m_name
;
}
/**
* Get the content type for this FileDesc.
*/
inline
std
::
optional
<
std
::
string
>
contentType
()
const
{
return
m_contentType
;
}
bool
operator
==
(
const
FileDesc
&
that
)
const
;
private
:
bool
m_inMemory
;
FileContent
m_content
;
std
::
optional
<
std
::
string
>
m_name
;
std
::
optional
<
std
::
string
>
m_contentType
;
};
class
DumbFileInterface
{
public
:
DumbFileProvider
getProviderFor
(
FileDesc
desc
)
const
;
};
class
FileInterface
{
public
:
/**
* Constructor.
*
* Construct a FileInterface using `o`.
*
* `o` should be of a type that has the getProviderFor()
* const method that takes a FileDesc and returns an object
* implicitly convertible to FileProvider. That is,
* the following should be well-formed:
* `[&o](FileDesc d) -> FileProvider { return static_cast<std::add_const_t<decltype(o)>>(o).getProviderFor(d); }`
*/
template
<
class
DeriveT
>
inline
FileInterface
(
DeriveT
&&
o
)
:
m_d
(
std
::
make_unique
<
Model
<
std
::
decay_t
<
DeriveT
>>>
(
std
::
forward
<
DeriveT
>
(
o
)))
{}
/**
* Get the provider for @c desc from this.
*
* @warning: You should not call this directly. This
* function is called by FileDesc::provider().
*/
inline
FileProvider
getProviderFor
(
FileDesc
desc
)
const
{
return
m_d
->
getProviderFor
(
std
::
move
(
desc
));
}
private
:
struct
Concept
{
virtual
~
Concept
()
=
default
;
virtual
FileProvider
getProviderFor
(
FileDesc
desc
)
const
=
0
;
};
template
<
class
DeriveT
>
struct
Model
:
public
Concept
{
explicit
Model
(
const
DeriveT
&
o
)
:
obj
(
o
)
{}
explicit
Model
(
DeriveT
&&
o
)
:
obj
(
std
::
move
(
o
))
{}
~
Model
()
override
=
default
;
FileProvider
getProviderFor
(
FileDesc
desc
)
const
override
{
return
obj
.
getProviderFor
(
std
::
move
(
desc
));
}
DeriveT
obj
;
};
std
::
unique_ptr
<
Concept
>
m_d
;
};
}
File Metadata
Details
Attached
Mime Type
text/x-c++
Expires
Tue, Jun 24, 10:52 PM (20 h, 32 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
234548
Default Alt Text
file-desc.hpp (10 KB)
Attached To
Mode
rL libkazv
Attached
Detach File
Event Timeline
Log In to Comment