Skip to content

Instantly share code, notes, and snippets.

@soareschen
Created July 16, 2025 15:05
Show Gist options
  • Save soareschen/d37d74b26ecd0709517a80a3fc97e2be to your computer and use it in GitHub Desktop.
Save soareschen/d37d74b26ecd0709517a80a3fc97e2be to your computer and use it in GitHub Desktop.
// This is a response on how to use Context-Generic Programming (CGP)
// to solve the specialization problem in the following blog post:
// https://oakchris1955.eu/posts/bypassing_specialization/
//
// More info available at https://contextgeneric.dev/.
use cgp::core::error::ErrorTypeProviderComponent;
use cgp::prelude::*;
// Redesign the FileSystem trait with CGP
#[cgp_component(FileSystemProvider)]
pub trait FileSystem: HasErrorType {
fn load_nth_sector(&mut self) -> Result<(), Self::Error>;
}
// The Read, Write, and Seek traits can also be provided by the context
#[cgp_component(Reader)]
pub trait CanRead: HasErrorType {
// todo
}
#[cgp_component(Seeker)]
pub trait CanSeek: HasErrorType {
// todo
}
#[cgp_component(Writer)]
pub trait CanWrite: HasErrorType {
// todo
}
// Define a read-only filesystem provider that depends on CanRead and CanSeek
#[cgp_new_provider]
impl<Context> FileSystemProvider<Context> for ReadOnlyFileSystem
where
Context: CanRead + CanSeek,
{
fn load_nth_sector(context: &mut Context) -> Result<(), Context::Error> {
todo!()
}
}
// Define a read-write filesystem provider that depends on CanRead, CanWrite, and CanSeek
#[cgp_new_provider]
impl<Context> FileSystemProvider<Context> for ReadWriteFileSystem
where
Context: CanRead + CanWrite + CanSeek,
{
fn load_nth_sector(context: &mut Context) -> Result<(), Context::Error> {
todo!()
}
}
// Dummy read, write, and seek providers. These can also be reused across different contexts,
// or multiple overlapping instances can be defined for different contexts.
#[cgp_new_provider]
impl<Context> Reader<Context> for DummyReader
where
Context: HasErrorType,
{
// todo
}
#[cgp_new_provider]
impl<Context> Writer<Context> for DummyWriter
where
Context: HasErrorType,
{
// todo
}
#[cgp_new_provider]
impl<Context> Seeker<Context> for DummySeeker
where
Context: HasErrorType,
{
// todo
}
// Define a read-only FAT filesystem context
#[cgp_context]
pub struct ReadOnlyFatFs {
// todo
}
// Use ReadOnlyFileSystem as the provider, together with wiring for reader and seeker components.
delegate_components! {
ReadOnlyFatFsComponents {
ErrorTypeProviderComponent:
UseType<std::io::Error>,
ReaderComponent:
DummyReader,
SeekerComponent:
DummySeeker,
FileSystemProviderComponent:
ReadOnlyFileSystem,
}
}
// Checks that the FileSystem component is implemented for ReadOnlyFatFs
check_components! {
CanUseReadOnlyFatFs for ReadOnlyFatFs {
FileSystemProviderComponent,
}
}
// Define a separate read-write FAT filesystem context
#[cgp_context]
pub struct ReadWriteFatFs {
// todo
}
// Use ReadWriteFileSystem as the provider, together with wiring that includes the writer component
delegate_components! {
ReadWriteFatFsComponents {
ErrorTypeProviderComponent:
UseType<std::io::Error>,
ReaderComponent:
DummyReader,
SeekerComponent:
DummySeeker,
WriterComponent:
DummyWriter,
FileSystemProviderComponent:
ReadWriteFileSystem,
}
}
// Checks that the FileSystem component is also implemented for ReadWriteFatFs
check_components! {
CanUseReadWriteFatFs for ReadWriteFatFs {
FileSystemProviderComponent,
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment