I’d try to outline behaviors and data-flow, avoid trying to replicate the module & trait architecture.
The set of organization features are too different to move cleanly between languages. Rust’s motivate a certain trait-focused approach which can be implemented in OCaml but with a lot of friction since it’s not meant to be used pervasively and requires composing manually. Same goes for Haskell since Rust’s approach copies a lot from it.
Detailed observations about the two languages organization features
Rust modules are weaker, meant to carry the role of namespacing and not much else. The main unit of abstraction is the function, so everything revolves around it. But there is a dual-personality enabled by impl blocks, for functions which are too coupled to the data they work on.
This results in a very specific approach: many small abstract interfaces that are composed together around the Self in single-instance top-level functions. Traits pay the cost of coherence and Self-centrism for their automatic ergonomics. Redundancy is met with macros or genericity. HOFs in APIs and throwaway functions are also not commonplace, although the stdlib borrows successful HOF-heavy interfaces like their iterators. HOFs in particular are often swapped for regular functions with composed trait constraints.
OCaml designs operate on a different granularity. Because modules themselves are highly capable and flexible tools of abstraction, and because they take the role of an interface, they get more emphasis. Modules are part of the set of objects you can manipulate freely in the language, so data & functions are relieved from that grouping role, and they tend to be much simpler to think about and compose as a consequence.
In effect, OCaml designs tend to be organized in more direct and sometimes tastefully redundant fashion: A generic func : {A : SomeTrait} -> A.t... could just be M1.func : M1.t... and M2.func : M2.t... and so on. Functions are thus more freely created and composed at a more granular level, and instead of writing one function that takes a composition of n interfaces, and having to implement those interfaces in full by all the types you care about, these choices, partial or full, are combinatorically available to you on both per-module and per-function basis.
Although t (Self-analogue) is commonplace, it’s not a requirement, which affords us more interface & grouping flexibility as well. A signature can have zero, one, or many type declarations.
Conformance to abstract interfaces is implicit by adding more functions to the module which satisfy said interface, or even overriding the module at a later point to suit your needs, relying on structural typing to narrow as needed. Interfaces themselves can be extended and narrowed in an expressive signature language. This results in changes that are more iterative and localized.
Multiple impls for the same type are fine and useful, newtyping is often unnecessary. HOFs as points of composition, throwaway functions and even throwaway modules, relying on more granular type (in)equalities as opposed to instance uniqueness, are all ways in which OCaml-written designs leverage its features.
OCaml is also more exception-happy which is awesome for decoupling error handling from business logic. Not a thing Rust codebases do. Better yet, our exceptions are incredibly cheap and can be used for control flow. Downside is of course that the bounds in which they can travel should be well-defined. So you might want to ask yourself about the error handling strategy instead of following rust’s Result approach verbatim.
In practice this means the point where you “get to writing code” tends to come faster in OCaml, because you can afford to ask about interfaces after the fact, not before being able to use them. Genericity is non-invasive and by-need.
Effectively Rust’s choice of features drives a tendency to over-abstract and over-conform to pre-existing interfaces from the get-go.
IMO there is high consistency and predictability in Rust code, but it requires some mental load to keep track of the fragmented sources of behavior in one unit of code. Luckily the resource-aware runtime & type system force developers to not get too happy with obtuse and impenetrable abstract code. OCaml codebases tend to be the most straightforward to read and conductive to localized reasoning, though more manual to write.