Index: uspace/lib/cpp/include/impl/functional.hpp
===================================================================
--- uspace/lib/cpp/include/impl/functional.hpp	(revision d2a66ae74301a90e120e736999161b58d5beaa1b)
+++ uspace/lib/cpp/include/impl/functional.hpp	(revision 9c00022939cd6fe804ba18bb99d8efedb49e0fce)
@@ -31,4 +31,6 @@
 
 #include <limits>
+#include <memory>
+#include <typeinfo>
 #include <type_traits>
 #include <utility>
@@ -753,4 +755,42 @@
      */
 
+    namespace aux
+    {
+        // TODO: fix this
+        /* template<class, class T, class... Args> */
+        /* struct is_callable_impl: false_type */
+        /* { /1* DUMMY BODY *1/ }; */
+
+        /* template<class, class R, class... Args> */
+        /* struct is_callable_impl< */
+        /*     void_t<decltype(aux::invoke(declval<R(Args...)>(), declval<Args>()..., R))>, */
+        /*     R, Args... */
+        /* > : true_type */
+        /* { /1* DUMMY BODY *1/ }; */
+
+        /* template<class T> */
+        /* struct is_callable: is_callable_impl<void_t<>, T> */
+        /* { /1* DUMMY BODY *1/ }; */
+
+        template<class Callable, class R, class... Args>
+        R invoke_callable(Callable* clbl, Args&&... args)
+        {
+            return (*clbl)(forward<Args>(args)...);
+        }
+
+        template<class Callable>
+        void copy_callable(Callable* to, Callable* from)
+        {
+            new(to) Callable{*from};
+        }
+
+        template<class Callable>
+        void destroy_callable(Callable* clbl)
+        {
+            if (clbl)
+                clbl->~Callable();
+        }
+    }
+
     class bad_function_call;
 
@@ -758,21 +798,287 @@
     class function; // undefined
 
+    /**
+     * Note: Ideally, this implementation wouldn't
+     *       copy the target if it was a pointer to
+     *       a function, but for the simplicity of the
+     *       implementation, we do copy even in that
+     *       case for now. It would be a nice optimization
+     *       if this was changed in the future.
+     */
     template<class R, class... Args>
-    class function<R(Args...)>;
+    class function<R(Args...)>
+    {
+        public:
+            using result_type = R;
+            // TODO: conditional typedefs
+
+            /**
+             * 20.9.12.2.1, construct/copy/destroy:
+             */
+
+            function() noexcept
+                : callable_{}, callable_size_{}, call_{},
+                  copy_{}, dest_{}
+            { /* DUMMY BODY */ }
+
+            function(nullptr_t) noexcept
+                : function{}
+            { /* DUMMY BODY */ }
+
+            function(const function& other)
+                : callable_{}, callable_size_{other.callable_size_},
+                  call_{other.call_}, copy_{other.copy_}, dest_{other.dest_}
+            {
+                callable_ = new uint8_t[callable_size_];
+                (*copy_)(callable_, other.callable_);
+            }
+
+            function(function&& other)
+                : callable_{other.callable_}, callable_size_{other.callable_size_},
+                  call_{other.call_}, copy_{other.copy_}, dest_{other.dest_}
+            {
+                other.callable_ = nullptr;
+                other.callable_size_ = size_t{};
+                other.call_ = nullptr;
+                other.copy_ = nullptr;
+                other.dest_ = nullptr;
+            }
+
+            // TODO: shall not participate in overloading unless aux::is_callable<F>
+            template<class F>
+            function(F f)
+                : callable_{}, callable_size_{sizeof(F)},
+                  call_{(call_t)aux::invoke_callable<F, R, Args...>},
+                  copy_{(copy_t)aux::copy_callable<F>},
+                  dest_{(dest_t)aux::destroy_callable<F>}
+            {
+                callable_ = new uint8_t[callable_size_];
+                (*copy_)(callable_, (uint8_t*)&f);
+            }
+
+            /**
+             * Note: For the moment we're ignoring the allocator
+             *       for simplicity of the implementation.
+             */
+
+            template<class A>
+            function(allocator_arg_t, const A& a) noexcept
+                : function{}
+            { /* DUMMY BODY */ }
+
+            template<class A>
+            function(allocator_arg_t, const A& a, nullptr_t) noexcept
+                : function{}
+            { /* DUMMY BODY */ }
+
+            template<class A>
+            function(allocator_arg_t, const A& a, const function& other)
+                : function{other}
+            { /* DUMMY BODY */ }
+
+            template<class A>
+            function(allocator_arg_t, const A& a, function&& other)
+                : function{move(other)}
+            { /* DUMMY BODY */ }
+
+            // TODO: shall not participate in overloading unless aux::is_callable<F>
+            template<class F, class A>
+            function(allocator_arg_t, const A& a, F f)
+                : function{f}
+            { /* DUMMY BODY */ }
+
+            function& operator=(const function& rhs)
+            {
+                function{rhs}.swap(*this);
+
+                return *this;
+            }
+
+            /**
+             * Note: We have to copy call_, copy_
+             *       and dest_ because they can be templated
+             *       by a type F we don't know.
+             */
+            function& operator=(function&& rhs)
+            {
+                clear_();
+
+                callable_ = rhs.callable_;
+                callable_size_ = rhs.callable_size_;
+                call_ = rhs.call_;
+                copy_ = rhs.copy_;
+                dest_ = rhs.dest_;
+
+                rhs.callable_ = nullptr;
+                rhs.callable_size_ = size_t{};
+                rhs.call_ = nullptr;
+                rhs.copy_ = nullptr;
+                rhs.dest_ = nullptr;
+
+                return *this;
+            }
+
+            function& operator=(nullptr_t) noexcept
+            {
+                clear_();
+
+                return *this;
+            }
+
+            // TODO: shall not participate in overloading unless aux::is_callable<F>
+            template<class F>
+            function& operator=(F&& f)
+            {
+                callable_size_ = sizeof(F);
+                callable_ = new uint8_t[callable_size_];
+                call_ = aux::invoke_callable<F, R, Args...>;
+                copy_ = aux::copy_callable<F>;
+                dest_ = aux::destroy_callable<F>;
+
+                (*copy_)(callable_, (uint8_t*)&f);
+            }
+
+            template<class F>
+            function& operator=(reference_wrapper<F> ref) noexcept
+            {
+                return (*this) = ref.get();
+            }
+
+            ~function()
+            {
+                if (callable_)
+                {
+                    (*dest_)(callable_);
+                    delete[] callable_;
+                }
+            }
+
+            /**
+             * 20.9.12.2.2, function modifiers:
+             */
+
+            void swap(function& other) noexcept
+            {
+                std::swap(callable_, other.callable_);
+                std::swap(callable_size_, other.callable_size_);
+                std::swap(call_, other.call_);
+                std::swap(copy_, other.copy_);
+                std::swap(dest_, other.dest_);
+            }
+
+            template<class F, class A>
+            void assign(F&& f, const A& a)
+            {
+                function{allocator_arg, a, forward<F>(f)}.swap(*this);
+            }
+
+            /**
+             * 20.9.12.2.3, function capacity:
+             */
+
+            explicit operator bool() const noexcept
+            {
+                return callable_ != nullptr;
+            }
+
+            /**
+             * 20.9.12.2.4, function invocation:
+             */
+
+            result_type operator()(Args... args) const
+            {
+                // TODO: throw bad_function_call if !callable_ || !call_
+                if constexpr (is_same_v<R, void>)
+                    (*call_)(callable_, forward<Args>(args)...);
+                else
+                    return (*call_)(callable_, forward<Args>(args)...);
+            }
+
+            /**
+             * 20.9.12.2.5, function target access:
+             */
+
+            const type_info& target_type() const noexcept
+            {
+                return typeid(*callable_);
+            }
+
+            template<class T>
+            T* target() noexcept
+            {
+                if (target_type() == typeid(T))
+                    return (T*)callable_;
+                else
+                    return nullptr;
+            }
+
+            template<class T>
+            const T* target() const noexcept
+            {
+                if (target_type() == typeid(T))
+                    return (T*)callable_;
+                else
+                    return nullptr;
+            }
+
+        private:
+            using call_t = R(*)(uint8_t*, Args&&...);
+            using copy_t = void (*)(uint8_t*, uint8_t*);
+            using dest_t = void (*)(uint8_t*);
+
+            uint8_t* callable_;
+            size_t callable_size_;
+            call_t call_;
+            copy_t copy_;
+            dest_t dest_;
+
+            void clear_()
+            {
+                if (callable_)
+                {
+                    (*dest_)(callable_);
+                    delete[] callable_;
+                    callable_ = nullptr;
+                }
+            }
+    };
+
+    /**
+     * 20.9.12.2.7, specialized algorithms:
+     */
 
     template<class R, class... Args>
-    void swap(function<R(Args...)>& f1, function<R(Args...)>& f2);
+    void swap(function<R(Args...)>& f1, function<R(Args...)>& f2)
+    {
+        f1.swap(f2);
+    }
+
+    /**
+     * 20.9.12.2.6, null pointer comparisons:
+     */
 
     template<class R, class... Args>
-    bool operator==(const function<R(Args...)>&, nullptr_t) noexcept;
+    bool operator==(const function<R(Args...)>& f, nullptr_t) noexcept
+    {
+        return !f;
+    }
 
     template<class R, class... Args>
-    bool operator==(nullptr_t, const function<R(Args...)>&) noexcept;
+    bool operator==(nullptr_t, const function<R(Args...)>& f) noexcept
+    {
+        return !f;
+    }
 
     template<class R, class... Args>
-    bool operator!=(const function<R(Args...)>&, nullptr_t) noexcept;
+    bool operator!=(const function<R(Args...)>& f, nullptr_t) noexcept
+    {
+        return (bool)f;
+    }
 
     template<class R, class... Args>
-    bool operator!=(nullptr_t, const function<R(Args...)>&) noexcept;
+    bool operator!=(nullptr_t, const function<R(Args...)>& f) noexcept
+    {
+        return (bool)f;
+    }
 
     /**
