Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Issue/336 transport iterfaces #343

Merged
merged 9 commits into from
Apr 25, 2024
Merged

Conversation

serges147
Copy link
Collaborator

First draft of transport interfaces

Added:

  • transport::ISession
  • transport::IMessage[Rx|Ts]Session
  • transport::I[Request|Response][Rx|Ts]Session

Also:

  • add "std: [14, 17, 20]" to the build matrix
  • add hash tag triggering by #verification #docs tags
  • strip repo absolute path prefix from doxygen file paths

serges147 and others added 5 commits April 5, 2024 11:04
Added:
- `transport::ISession`
- `transport::IMessage[Rx|Ts]Session`
- `transport::I[Request|Response][Rx|Ts]Session`

Also:
- add "std: [14, 17, 20]" to the build matrix
- add hash tag triggering by #verification #docs tags
- strip repo absolute path prefix from doxygen file paths #docs

---------

Co-authored-by: Sergei Shirokov <[email protected]>
- Added `ITransport::makeMessage[Rx|Tx]Session` methods
- Added `ITransport::make[Request|Response][Rx|Tx]Session` methods
- Added `Priority`, `[Service]TransferMetadata`, `PayloadFragments`,
`MessageRxTransfre` and `ServiceRxTransfer` types.
- Added`transport::AnyError`
- Added implementation of `DynamicBuffer`.

Also:
- fixed "Coverage" build flavor, and artifacts upload
- added `libcyphal::UniquePtr` & `libcyphal::Expected`
- fixed "rule of five" deficiency
- Added `ITransport`, `ICanTransport` & `IUpdTransport`
- `PayloadFragment` now immutable; `FragmentBuffer` is mutable span.
- `canardInit` is in use.
- CAN transport memory resource is connected to the canard
allocate/free.
- Implemented `getLocalNodeId`

Also:
- Get rid of extra `Factory` entities.
- `cetl::VariableLengthArray` is now in use to store CAN transport media
interfaces.
- min MTU from all media is reported by the
`ICanTransport::getProtocolParams`.
- added corresponding unit tests (to cover `getProtocolParams`).

Also:
- a bit reworked (simplified) canard memory alloc/free
@serges147 serges147 self-assigned this Apr 15, 2024
pavel-kirienko
pavel-kirienko previously approved these changes Apr 15, 2024
.github/workflows/tests.yml Outdated Show resolved Hide resolved
include/libcyphal/transport/defines.hpp Show resolved Hide resolved
test/unittest/CMakeLists.txt Outdated Show resolved Hide resolved
pavel-kirienko
pavel-kirienko previously approved these changes Apr 16, 2024
@pavel-kirienko pavel-kirienko linked an issue Apr 16, 2024 that may be closed by this pull request
Copy link
Contributor

@thirtytwobits thirtytwobits left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's a complete lack of interesting ASCII art in this source so far. Very boring!

include/libcyphal/transport/defines.hpp Show resolved Hide resolved
include/libcyphal/transport/dynamic_buffer.hpp Outdated Show resolved Hide resolved
CETL_NODISCARD virtual cetl::optional<MessageRxTransfer> receive() = 0;
};

class IMessageTxSession : public IRunnable
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same comment here as the previous review and for all types in this PR: please start with interface and class documentation. This provides us with a mini-design review as we can state the contract without having the implementation written yet.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is sensible but:

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As, I wrote for other PR, documentation for public stuff is definitely coming, but I believe we first need some more or less stable api agreed upon. Design doc is very good and very insightful, but at the same time sometimes leaves some (devil in) details unspecified, which might affect result interfaces/implementation quite significantly (like we already discussing about error handling strategies).

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's mostly the class-level documentation that I'm struggling with. I'm left to linking your intentions in these PRs with a single word – the class name – against the design document. If you have to c&p from that document it's fine just help me out with some context when you first define a class, interface, or data structure.

include/libcyphal/transport/can/media.hpp Outdated Show resolved Hide resolved
include/libcyphal/transport/can/media.hpp Outdated Show resolved Hide resolved
include/libcyphal/transport/can/media.hpp Show resolved Hide resolved
include/libcyphal/transport/can/transport.hpp Show resolved Hide resolved
include/libcyphal/transport/can/transport.hpp Show resolved Hide resolved
include/libcyphal/transport/can/transport.hpp Show resolved Hide resolved
test/unittest/transport/can/media_mock.hpp Show resolved Hide resolved
1. Less `auto` according AUTOSAR A7-1-5
2. Less `struct` according AUTOSAR A11-0-2
3. C.35: A base class destructor should be either public and virtual, or protected and non-virtual.
4. `IMedia::setFilters` now fallible.
pavel-kirienko
pavel-kirienko previously approved these changes Apr 22, 2024

protected:
IRunnable() = default;
virtual ~IRunnable() = default;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's sorta a nitpick but per Core Cpp Guidelines C35 the ~IRunnable() shouldn't be virtual. Can we establish this as a standard in this codebase too?

Copy link
Collaborator Author

@serges147 serges147 Apr 22, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's a bit tricky (for me at least) to decide when we want destructor accessible and when we don't... Even for interfaces we currently do move them into unique_ptr<Concrete>unique_ptr<Interface> which will require them public.

Copy link
Contributor

@thirtytwobits thirtytwobits Apr 22, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We shouldn't manage the lifecycle of an object through it's interface. This can lead to dangerous assumptions and amputations (https://godbolt.org/z/1Tj4nzehd). This is what the voldemort_ptr, dark-ptr, interface_ptr type is meant to solve.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank You Scott for very representable example (with legless dog). Please see latest commit where I moved destructors for "external" entities (IMedia-s and IMultiplexer) to protected area. BUT, I can't currently do the same for IRunnable up to various IXxxSession-s we return to user as unique ptrs. This is b/c of our current pmr implementation of UniquePtr - it REQUIRES currently that ~Interface will be available for deleter. The only way I see to remove such requirement is to have type-erased deleter which will capture in a closure original concrete type allocator. It will require cetl::function (not yet available). IMHO it has to be type-erased - otherwise we can't have proper UniquePtr<IX>UniquePtr<IY> conversions (assuming of course that X and Y convertible). I discussed this with Pavel - it seems that he agrees with me.

BTW, such type-erased deleter should also solve current standing issue OpenCyphal/CETL#118 (see 2nd bullet)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Okay. Let's track this with TODOs in the code. Perhaps I'll take on this work in CETL. It'll give me a reason to move my godbolt example into github.

IMedia(const IMedia&) = delete;
IMedia& operator=(IMedia&&) = delete;
IMedia& operator=(const IMedia&) = delete;
virtual ~IMedia() = default;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

protected/non-virtual

Copy link
Contributor

@thirtytwobits thirtytwobits left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Generally all good here. Please tighten up the interface destructors as this can be hard to fix as the design evolved.

The biggest issue is the open issue on media-layer memory ownership. If we need a interim design call I can do that.

/// Copyright Amazon.com Inc. or its affiliates.
/// SPDX-License-Identifier: MIT

#ifndef LIBCYPHAL_TRANSPORT_DEFINES_HPP_INCLUDED
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can we call this types.hpp instead? We specifically do not want #defines

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I will rename it in the next (347) pr.

IMultiplexer(const IMultiplexer&) = delete;
IMultiplexer& operator=(IMultiplexer&&) = delete;
IMultiplexer& operator=(const IMultiplexer&) = delete;
virtual ~IMultiplexer() = default;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same here. Interface destructors should always be protected/non-virtual

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I get it for external entity interfaces (like media and multiplexer), but for our own entities we implement (and return them via makeXxx as unique ptrs) it still blurry which pattern to use.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Internal implementations would not be destructed via the interface though? They would use their complete internal types.


// MARK: IRunnable

void run(const TimePoint) override {}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

prefer final to override. If actually using override document how subclasses must handle the base-class implementation (e.g. they shall-or-shall-not invoke it. They shall-invoke it first/last. etc).

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

At class level we have final - afaik it means that all the virtual methods are final as well. do you want make it even more explicit?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

About "shall-or-shall-not invoke" I can't comment yet (due to lack of fine understanding of requirements), but I agree we should have (eventually) such documentation.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Eh. I guess if the class is final the sure. It's fine.

Copy link
Contributor

@thirtytwobits thirtytwobits left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As discussed on call: we have the right issues captured now to ensure my overarching concerns will be addressed moving forward

Interface() = default;
Interface(Interface&&) noexcept = default;
Interface& operator=(Interface&&) noexcept = default;

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the rule of 5 requires the dtor to be explicitly defaulted

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

will do it at after-next pr

@serges147 serges147 added this pull request to the merge queue Apr 25, 2024
Merged via the queue into main with commit ee5f1e2 Apr 25, 2024
45 checks passed
@serges147 serges147 deleted the issue/336_transport_iterfaces branch April 25, 2024 13:38
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Declare libcyphal transport interfaces
4 participants