Add file_stdio and File concept

This commit is contained in:
Vinnie Falco
2017-07-05 20:30:18 -07:00
parent aff5f392e2
commit ddc3099281
17 changed files with 971 additions and 2 deletions

View File

@ -1,3 +1,9 @@
Version 74:
* Add file_stdio and File concept
--------------------------------------------------------------------------------
Version 73:
* Jamroot tweak

View File

@ -60,6 +60,7 @@
[def __DynamicBuffer__ [link beast.concept.DynamicBuffer [*DynamicBuffer]]]
[def __Fields__ [link beast.concept.Fields [*Fields]]]
[def __FieldsReader__ [link beast.concept.FieldsReader [*FieldsReader]]]
[def __File__ [link beast.concept.File [*File]]]
[def __Stream__ [link beast.concept.streams [*Stream]]]
[def __SyncStream__ [link beast.concept.streams.SyncStream [*SyncStream]]]
@ -77,13 +78,14 @@
[def __static_buffer__ [link beast.ref.beast__static_buffer `static_buffer`]]
[def __static_buffer_n__ [link beast.ref.beast__static_buffer_n `static_buffer_n`]]
[import ../example/doc/http_examples.hpp]
[import ../example/echo-op/echo_op.cpp]
[import ../example/common/detect_ssl.hpp]
[import ../example/common/file_body.hpp]
[import ../example/doc/http_examples.hpp]
[import ../example/echo-op/echo_op.cpp]
[import ../example/http-client/http_client.cpp]
[import ../example/websocket-client/websocket_client.cpp]
[import ../test/exemplars.cpp]
[import ../test/core/doc_snippets.cpp]
[import ../test/http/doc_snippets.cpp]

View File

@ -13,6 +13,7 @@ This section describes all of the concepts defined by the library.
[include concept/BodyReader.qbk]
[include concept/BodyWriter.qbk]
[include concept/BufferSequence.qbk]
[include concept/File.qbk]
[include concept/DynamicBuffer.qbk]
[include concept/Fields.qbk]
[include concept/FieldsReader.qbk]

173
doc/concept/File.qbk Normal file
View File

@ -0,0 +1,173 @@
[/
Copyright (c) 2013-2016 Vinnie Falco (vinnie dot falco at gmail dot com)
Distributed under the Boost Software License, Version 1.0. (See accompanying
file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
]
[section:File File]
The [*File] concept abstracts access to files in the underlying file system.
To support other platform interfaces, users may author their own [*File]
types which meet these requirements.
In this table:
* `F` is a [*File] type
* `f` is an instance of `F`
* `p` is a value of type `char const*` which points to a null
terminated utf-8 encoded string.
* `m` is an instance of [link beast.ref.beast__file_mode `file_mode`]
* `n` is a number of bytes, convertible to `std::size_t`
* `o` is a byte offset in the file, convertible to `std::uint64_t`
* `b` is any non-const pointer to memory
* `c` is any possibly-const pointer to memory
* `ec` is a reference of type [link beast.ref.beast__error_code `error_code`]
[heading Associated Types]
* [link beast.ref.beast__file_mode `file_mode`]
* [link beast.ref.beast__is_file `is_file`]
[heading File Requirements]
[table Valid Expressions
[[Operation] [Return Type] [Semantics, Pre/Post-conditions]]
[
[`F()`]
[ ]
[
Default constructable
]
]
[
[`f.~F()`]
[ ]
[
Destructible.
If `f` refers to an open file, it is first closed
as if by a call to `close` with the error ignored.
]
]
[
[`f.is_open()`]
[`bool`]
[
Returns `true` if `f` refers to an open file, `false` otherwise.
]
]
[
[`f.close(ec)`]
[]
[
If `f` refers to an open file, thie function attempts to
close the file.
Regardless of whether an error occurs or not, a subsequent
call to `f.is_open()` will return `false`.
The function will ensure that `!ec` is `true` if there was
no error or set to the appropriate error code if an error
occurred.
]
]
[
[`f.open(p,m,ec)`]
[]
[
Attempts to open the file at the path specified by `p`
with the mode specified by `m`.
Upon success, a subsequent call to `f.is_open()` will
return `true`.
If `f` refers to an open file, it is first closed
as if by a call to `close` with the error ignored.
The function will ensure that `!ec` is `true` if there was
no error or set to the appropriate error code if an error
occurred.
]
]
[
[`f.size(ec)`]
[`std::uint64_t`]
[
If `f` refers to an open file, this function attempts to
determine the file size and return its value.
If `f` does not refer to an open file, the function will
set `ec` to `errc::invalid_argument` and return 0.
The function will ensure that `!ec` is `true` if there was
no error or set to the appropriate error code if an error
occurred.
]
]
[
[`f.pos(ec)`]
[`std::uint64_t`]
[
If `f` refers to an open file, this function attempts to
determine the current file offset and return it.
If `f` does not refer to an open file, the function will
set `ec` to `errc::invalid_argument` and return 0.
The function will ensure that `!ec` is `true` if there was
no error or set to the appropriate error code if an error
occurred.
]
]
[
[`f.seek(o,ec)`]
[]
[
Attempts to reposition the current file offset to the value
`o`, which represents a byte offset relative to the beginning
of the file.
If `f` does not refer to an open file, the function will
set `ec` to `errc::invalid_argument` and return immediately.
The function will ensure that `!ec` is `true` if there was
no error or set to the appropriate error code if an error
occurred.
]
]
[
[`f.read(b,n,ec)`]
[`std::size_t`]
[
Attempts to read `n` bytes starting at the current file offset
from the open file referred to by `f`.
Bytes read are stored in the memory buffer at address `b` which
must be at least `n` bytes in size.
The function advances the file offset by the amount read, and
returns the number of bytes actually read, which may be less
than `n`.
If `f` does not refer to an open file, the function will
set `ec` to `errc::invalid_argument` and return immediately.
The function will ensure that `!ec` is `true` if there was
no error or set to the appropriate error code if an error
occurred.
]
]
[
[`f.write(c,n,ec)`]
[`std::size_t`]
[
Attempts to write `n` bytes from the buffer pointed to by `c` to
the current file offset of the open file referred to by `f`.
The memory buffer at `c` must point to storage of at least `n`
bytes meant to be copied to the file.
The function advances the file offset by the amount written,
and returns the number of bytes actually written, which may be
less than `n`.
If `f` does not refer to an open file, the function will
set `ec` to `errc::invalid_argument` and return immediately.
The function will ensure that `!ec` is `true` if there was
no error or set to the appropriate error code if an error
occurred.
]
]
]
[heading Exemplar]
[concept_File]
[heading Models]
* [link beast.ref.beast__file_stdio `file_stdio`]
[endsect]

View File

@ -173,11 +173,13 @@
<member><link linkend="beast.ref.beast__error_category">error_category</link></member>
<member><link linkend="beast.ref.beast__error_code">error_code</link></member>
<member><link linkend="beast.ref.beast__error_condition">error_condition</link></member>
<member><link linkend="beast.ref.beast__file">file</link></member>
</simplelist>
</entry>
<entry valign="top">
<bridgehead renderas="sect3">&nbsp;</bridgehead>
<simplelist type="vert" columns="1">
<member><link linkend="beast.ref.beast__file_stdio">file_stdio</link></member>
<member><link linkend="beast.ref.beast__flat_buffer">flat_buffer</link></member>
<member><link linkend="beast.ref.beast__handler_alloc">handler_alloc</link></member>
<member><link linkend="beast.ref.beast__handler_ptr">handler_ptr</link></member>
@ -211,6 +213,7 @@
<bridgehead renderas="sect3">Constants</bridgehead>
<simplelist type="vert" columns="1">
<member><link linkend="beast.ref.beast__errc">errc</link></member>
<member><link linkend="beast.ref.beast__file_mode">file_mode</link></member>
</simplelist>
</entry>
<entry valign="top">
@ -224,6 +227,7 @@
<member><link linkend="beast.ref.beast__is_completion_handler">is_completion_handler</link></member>
<member><link linkend="beast.ref.beast__is_const_buffer_sequence">is_const_buffer_sequence</link></member>
<member><link linkend="beast.ref.beast__is_dynamic_buffer">is_dynamic_buffer</link></member>
<member><link linkend="beast.ref.beast__is_file">is_file</link></member>
<member><link linkend="beast.ref.beast__is_mutable_buffer_sequence">is_mutable_buffer_sequence</link></member>
<member><link linkend="beast.ref.beast__is_sync_read_stream">is_sync_read_stream</link></member>
<member><link linkend="beast.ref.beast__is_sync_stream">is_sync_stream</link></member>
@ -236,6 +240,7 @@
<member><link linkend="beast.concept.streams.AsyncStream">AsyncStream</link></member>
<member><link linkend="beast.concept.BufferSequence">BufferSequence</link></member>
<member><link linkend="beast.concept.DynamicBuffer">DynamicBuffer</link></member>
<member><link linkend="beast.concept.File">File</link></member>
<member><link linkend="beast.concept.streams.Stream">Stream</link></member>
<member><link linkend="beast.concept.streams.SyncStream">SyncStream</link></member>
</simplelist>

View File

@ -19,6 +19,9 @@
#include <beast/core/consuming_buffers.hpp>
#include <beast/core/drain_buffer.hpp>
#include <beast/core/error.hpp>
#include <beast/core/file.hpp>
#include <beast/core/file_base.hpp>
#include <beast/core/file_stdio.hpp>
#include <beast/core/flat_buffer.hpp>
#include <beast/core/handler_alloc.hpp>
#include <beast/core/handler_ptr.hpp>

View File

@ -0,0 +1,25 @@
//
// Copyright (c) 2015-2016 Vinnie Falco (vinnie dot falco at gmail dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
#ifndef BEAST_CORE_FILE_HPP
#define BEAST_CORE_FILE_HPP
#include <beast/core/file_base.hpp>
#include <beast/core/file_stdio.hpp>
namespace beast {
/** An implementation of File.
This alias is set to the best available implementation
of @b File given the platform and build settings.
*/
using file = file_stdio;
} // beast
#endif

View File

@ -0,0 +1,87 @@
//
// Copyright (c) 2015-2016 Vinnie Falco (vinnie dot falco at gmail dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
#ifndef BEAST_CORE_FILE_BASE_HPP
#define BEAST_CORE_FILE_BASE_HPP
#include <beast/core/string.hpp>
namespace beast {
/// The type of file path used by the library
using file_path = string_view;
/** File open modes
These modes are used when opening files using
instances of the @b File concept.
@see file_stdio
*/
enum class file_mode
{
/// Random reading
read,
/// Sequential reading
scan,
/** Random writing to a new or truncated file
@li If the file does not exist, it is created.
@li If the file exists, it is truncated to
zero size upon opening.
*/
write,
/** Random writing to new file only
If the file exists, an error is generated.
*/
write_new,
/** Random writing to existing file
If the file does not exist, an error is generated.
*/
write_existing,
/** Appending to a new or truncated file
The current file position shall be set to the end of
the file prior to each write.
@li If the file does not exist, it is created.
@li If the file exists, it is truncated to
zero size upon opening.
*/
append,
/** Appending to a new file only
The current file position shall be set to the end of
the file prior to each write.
If the file exists, an error is generated.
*/
append_new,
/** Appending to an existing file
The current file position shall be set to the end of
the file prior to each write.
If the file does not exist, an error is generated.
*/
append_existing
};
} // beast
#endif

View File

@ -0,0 +1,153 @@
//
// Copyright (c) 2015-2016 Vinnie Falco (vinnie dot falco at gmail dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
#ifndef BEAST_CORE_FILE_STDIO_HPP
#define BEAST_CORE_FILE_STDIO_HPP
#include <beast/core/error.hpp>
#include <beast/core/file_base.hpp>
#include <cstdio>
#include <cstdint>
namespace beast {
/** An implementation of File which uses cstdio.
This class implements a file using the interfaces present
in the C++ Standard Library, in `<stdio>`.
*/
class file_stdio
{
FILE* f_ = nullptr;
public:
/** The type of the underlying file handle.
This is platform-specific.
*/
using native_handle_type = FILE*;
/** Destructor
If the file is open it is first closed.
*/
~file_stdio();
/** Constructor
There is no open file initially.
*/
file_stdio() = default;
/** Constructor
The moved-from object behaves as if default constructed.
*/
file_stdio(file_stdio&& other);
/** Assignment
The moved-from object behaves as if default constructed.
*/
file_stdio& operator=(file_stdio&& other);
/// Returns the native handle associated with the file.
FILE*
native_handle() const
{
return f_;
}
/** Set the native handle associated with the file.
If the file is open it is first closed.
@param f The native file handle to assign.
*/
void
native_handle(FILE* f);
/// Returns `true` if the file is open
bool
is_open() const
{
return f_ != nullptr;
}
/** Close the file if open
@param ec Set to the error, if any occurred.
*/
void
close(error_code& ec);
/** Open a file at the given path with the specified mode
@param path The utf-8 encoded path to the file
@param mode The file mode to use
@param ec Set to the error, if any occurred
*/
void
open(char const* path, file_mode mode, error_code& ec);
/** Return the size of the open file
@param ec Set to the error, if any occurred
@return The size in bytes
*/
std::uint64_t
size(error_code& ec) const;
/** Return the current position in the open file
@param ec Set to the error, if any occurred
@return The offset in bytes from the beginning of the file
*/
std::uint64_t
pos(error_code& ec) const;
/** Adjust the current position in the open file
@param offset The offset in bytes from the beginning of the file
@param ec Set to the error, if any occurred
*/
void
seek(std::uint64_t offset, error_code& ec);
/** Read from the open file
@param buffer The buffer for storing the result of the read
@param n The number of bytes to read
@param ec Set to the error, if any occurred
*/
std::size_t
read(void* buffer, std::size_t n, error_code& ec) const;
/** Write to the open file
@param buffer The buffer holding the data to write
@param n The number of bytes to write
@param ec Set to the error, if any occurred
*/
std::size_t
write(void const* buffer, std::size_t n, error_code& ec);
};
} // beast
#include <beast/core/impl/file_stdio.ipp>
#endif

View File

@ -0,0 +1,225 @@
//
// Copyright (c) 2015-2016 Vinnie Falco (vinnie dot falco at gmail dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
#ifndef BEAST_CORE_IMPL_FILE_STDIO_IPP
#define BEAST_CORE_IMPL_FILE_STDIO_IPP
#include <limits>
namespace beast {
inline
file_stdio::
~file_stdio()
{
if(f_)
fclose(f_);
}
inline
file_stdio::
file_stdio(file_stdio&& other)
: f_(other.f_)
{
other.f_ = nullptr;
}
inline
file_stdio&
file_stdio::
operator=(file_stdio&& other)
{
if(&other == this)
return *this;
if(f_)
fclose(f_);
f_ = other.f_;
other.f_ = nullptr;
return *this;
}
inline
void
file_stdio::
native_handle(FILE* f)
{
if(f_)
fclose(f_);
f_ = f;
}
inline
void
file_stdio::
close(error_code& ec)
{
if(f_)
{
int failed = fclose(f_);
f_ = nullptr;
if(failed)
{
ec.assign(errno, generic_category());
return;
}
}
ec.assign(0, ec.category());
}
inline
void
file_stdio::
open(char const* path, file_mode mode, error_code& ec)
{
if(f_)
{
fclose(f_);
f_ = nullptr;
}
char const* s;
switch(mode)
{
default:
case file_mode::read: s = "rb"; break;
case file_mode::scan: s = "rb"; break;
case file_mode::write: s = "wb"; break;
case file_mode::write_new: s = "wbx"; break;
case file_mode::write_existing: s = "wb"; break;
case file_mode::append: s = "ab"; break;
case file_mode::append_new: s = "abx"; break;
case file_mode::append_existing: s = "ab"; break;
}
f_ = std::fopen(path, s);
if(! f_)
{
ec.assign(errno, generic_category());
return;
}
ec.assign(0, ec.category());
}
inline
std::uint64_t
file_stdio::
size(error_code& ec) const
{
if(! f_)
{
ec.assign(errc::invalid_argument, generic_category());
return 0;
}
long pos = std::ftell(f_);
if(pos == -1L)
{
ec.assign(errno, generic_category());
return 0;
}
int result = std::fseek(f_, 0, SEEK_END);
if(result != 0)
{
ec.assign(errno, generic_category());
return 0;
}
long size = std::ftell(f_);
if(size == -1L)
{
ec.assign(errno, generic_category());
std::fseek(f_, pos, SEEK_SET);
return 0;
}
result = std::fseek(f_, pos, SEEK_SET);
if(result != 0)
ec.assign(errno, generic_category());
else
ec.assign(0, ec.category());
return size;
}
inline
std::uint64_t
file_stdio::
pos(error_code& ec) const
{
if(! f_)
{
ec.assign(errc::invalid_argument, generic_category());
return 0;
}
long pos = std::ftell(f_);
if(pos == -1L)
{
ec.assign(errno, generic_category());
return 0;
}
ec.assign(0, ec.category());
return pos;
}
inline
void
file_stdio::
seek(std::uint64_t offset, error_code& ec)
{
if(! f_)
{
ec.assign(errc::invalid_argument, generic_category());
return;
}
if(offset > (std::numeric_limits<long>::max)())
{
ec = make_error_code(errc::invalid_seek);
return;
}
int result = std::fseek(f_,
static_cast<long>(offset), SEEK_SET);
if(result != 0)
ec.assign(errno, generic_category());
else
ec.assign(0, ec.category());
}
inline
std::size_t
file_stdio::
read(void* buffer, std::size_t n, error_code& ec) const
{
if(! f_)
{
ec.assign(errc::invalid_argument, generic_category());
return 0;
}
auto nread = std::fread(buffer, 1, n, f_);
if(std::ferror(f_))
{
ec.assign(errno, generic_category());
return 0;
}
return nread;
}
inline
std::size_t
file_stdio::
write(void const* buffer, std::size_t n, error_code& ec)
{
if(! f_)
{
ec.assign(errc::invalid_argument, generic_category());
return 0;
}
auto nwritten = std::fwrite(buffer, 1, n, f_);
if(std::ferror(f_))
{
ec.assign(errno, generic_category());
return 0;
}
return nwritten;
}
} // beast
#endif

View File

@ -9,6 +9,7 @@
#define BEAST_TYPE_TRAITS_HPP
#include <beast/config.hpp>
#include <beast/core/file_base.hpp>
#include <beast/core/detail/type_traits.hpp>
#include <boost/asio/buffer.hpp>
#include <type_traits>
@ -558,6 +559,75 @@ using is_sync_stream = std::integral_constant<bool,
is_sync_read_stream<T>::value && is_sync_write_stream<T>::value>;
#endif
//------------------------------------------------------------------------------
//
// File concepts
//
//------------------------------------------------------------------------------
/** Determine if `T` meets the requirements of @b File.
Metafunctions are used to perform compile time checking of template
types. This type will be `std::true_type` if `T` meets the requirements,
else the type will be `std::false_type`.
@par Example
Use with `static_assert`:
@code
template<class File>
void f(File& file)
{
static_assert(is_file<File>::value,
"File requirements not met");
...
@endcode
Use with `std::enable_if` (SFINAE):
@code
template<class File>
typename std::enable_if<is_file<File>::value>::type
f(File& file);
@endcode
*/
#if BEAST_DOXYGEN
template<class T>
struct is_file : std::integral_constant<bool, ...>{};
#else
template<class T, class = void>
struct is_file : std::false_type {};
template<class T>
struct is_file<T, detail::void_t<decltype(
std::declval<bool&>() = std::declval<T const&>().is_open(),
std::declval<T&>().close(std::declval<error_code&>()),
std::declval<T&>().open(
std::declval<char const*>(),
std::declval<file_mode>(),
std::declval<error_code&>()),
std::declval<std::uint64_t&>() = std::declval<T&>().size(
std::declval<error_code&>()),
std::declval<std::uint64_t&>() = std::declval<T&>().pos(
std::declval<error_code&>()),
std::declval<T&>().seek(
std::declval<std::uint64_t>(),
std::declval<error_code&>()),
std::declval<std::size_t&>() = std::declval<T&>().read(
std::declval<void*>(),
std::declval<std::size_t>(),
std::declval<error_code&>()),
std::declval<std::size_t&>() = std::declval<T&>().write(
std::declval<void const*>(),
std::declval<std::size_t>(),
std::declval<error_code&>()),
(void)0)>> : std::integral_constant<bool,
std::is_default_constructible<T>::value &&
std::is_destructible<T>::value
> {};
#endif
} // beast
#endif

View File

@ -24,6 +24,9 @@ add_executable (core-tests
doc_snippets.cpp
drain_buffer.cpp
error.cpp
file.cpp
file_stdio.cpp
file_test.hpp
flat_buffer.cpp
handler_alloc.cpp
handler_ptr.cpp

View File

@ -19,6 +19,8 @@ unit-test core-tests :
doc_snippets.cpp
drain_buffer.cpp
error.cpp
file.cpp
file_stdio.cpp
flat_buffer.cpp
handler_alloc.cpp
handler_ptr.cpp

9
test/core/file.cpp Normal file
View File

@ -0,0 +1,9 @@
//
// Copyright (c) 2013-2017 Vinnie Falco (vinnie dot falco at gmail dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
// Test that header file is self-contained.
#include <beast/core/file.hpp>

31
test/core/file_stdio.cpp Normal file
View File

@ -0,0 +1,31 @@
//
// Copyright (c) 2013-2016 Vinnie Falco (vinnie dot falco at gmail dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
// Test that header file is self-contained.
#include <beast/core/file_stdio.hpp>
#include "file_test.hpp"
#include <beast/core/type_traits.hpp>
#include <beast/unit_test/suite.hpp>
namespace beast {
class file_stdio_test
: public beast::unit_test::suite
{
public:
void
run()
{
doTestFile<file_stdio>(*this);
}
};
BEAST_DEFINE_TESTSUITE(file_stdio,core,beast);
} // beast

122
test/core/file_test.hpp Normal file
View File

@ -0,0 +1,122 @@
//
// Copyright (c) 2013-2016 Vinnie Falco (vinnie dot falco at gmail dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
#ifndef BEAST_TEST_CORE_FILE_TEST_HPP
#define BEAST_TEST_CORE_FILE_TEST_HPP
#include <beast/core/type_traits.hpp>
#include <beast/unit_test/suite.hpp>
#include <boost/config.hpp>
#include <boost/filesystem.hpp>
#include <string>
namespace beast {
template<class File>
void
doTestFile(beast::unit_test::suite& test)
{
BOOST_STATIC_ASSERT(is_file<File>::value);
error_code ec;
auto const temp = boost::filesystem::unique_path();
{
{
File f1;
test.BEAST_EXPECT(! f1.is_open());
f1.open(temp.string<std::string>().c_str(), file_mode::write, ec);
test.BEAST_EXPECT(! ec);
File f2{std::move(f1)};
test.BEAST_EXPECT(! f1.is_open());
test.BEAST_EXPECT(f2.is_open());
File f3;
f3 = std::move(f2);
test.BEAST_EXPECT(! f2.is_open());
test.BEAST_EXPECT(f3.is_open());
f1.close(ec);
test.BEAST_EXPECT(! ec);
auto const temp2 = boost::filesystem::unique_path();
f3.open(temp2.string<std::string>().c_str(), file_mode::read, ec);
test.BEAST_EXPECT(ec);
ec.assign(0, ec.category());
}
boost::filesystem::remove(temp, ec);
test.BEAST_EXPECT(! ec);
}
File f;
test.BEAST_EXPECT(! f.is_open());
f.size(ec);
test.BEAST_EXPECT(ec == errc::invalid_argument);
ec.assign(0, ec.category());
f.pos(ec);
test.BEAST_EXPECT(ec == errc::invalid_argument);
ec.assign(0, ec.category());
f.seek(0, ec);
test.BEAST_EXPECT(ec == errc::invalid_argument);
ec.assign(0, ec.category());
f.read(nullptr, 0, ec);
test.BEAST_EXPECT(ec == errc::invalid_argument);
ec.assign(0, ec.category());
f.write(nullptr, 0, ec);
test.BEAST_EXPECT(ec == errc::invalid_argument);
ec.assign(0, ec.category());
f.open(temp.string<std::string>().c_str(), file_mode::write, ec);
test.BEAST_EXPECT(! ec);
std::string const s = "Hello, world!";
f.write(s.data(), s.size(), ec);
test.BEAST_EXPECT(! ec);
auto size = f.size(ec);
test.BEAST_EXPECT(! ec);
test.BEAST_EXPECT(size == s.size());
auto pos = f.pos(ec);
test.BEAST_EXPECT(! ec);
test.BEAST_EXPECT(pos == size);
f.close(ec);
test.BEAST_EXPECT(! ec);
f.open(temp.string<std::string>().c_str(), file_mode::read, ec);
test.BEAST_EXPECT(! ec);
std::string buf;
buf.resize(s.size());
f.read(&buf[0], buf.size(), ec);
test.BEAST_EXPECT(! ec);
test.BEAST_EXPECT(buf == s);
f.seek(1, ec);
test.BEAST_EXPECT(! ec);
buf.resize(3);
f.read(&buf[0], buf.size(), ec);
test.BEAST_EXPECT(! ec);
test.BEAST_EXPECT(buf == "ell");
pos = f.pos(ec);
test.BEAST_EXPECT(! ec);
test.BEAST_EXPECT(pos == 4);
f.close(ec);
test.BEAST_EXPECT(! ec);
boost::filesystem::remove(temp, ec);
test.BEAST_EXPECT(! ec);
}
} // beast
#endif

View File

@ -6,6 +6,7 @@
//
#include <beast/core/error.hpp>
#include <beast/core/file_base.hpp>
#include <beast/http/message.hpp>
#include <beast/http/type_traits.hpp>
#include <boost/optional.hpp>
@ -244,5 +245,56 @@ struct FieldsReader
//]
};
//[concept_File
struct File
{
/** Default constructor
There is no open file initially.
*/
File();
/** Destructor
If the file is open it is first closed.
*/
~File();
/// Returns `true` if the file is open
bool
is_open() const;
/// Close the file if open
void
close(error_code& ec);
/// Open a file at the given path with the specified mode
void
open(char const* path, file_mode mode, error_code& ec);
/// Return the size of the open file
std::uint64_t
size(error_code& ec) const;
/// Return the current position in the open file
std::uint64_t
pos(error_code& ec) const;
/// Adjust the current position in the open file
void
seek(std::uint64_t offset, error_code& ec);
/// Read from the open file
std::size_t
read(void* buffer, std::size_t n, error_code& ec) const;
/// Write to the open file
std::size_t
write(void const* buffer, std::size_t n, error_code& ec);
};
//]
} // http
} // beast