10 подписчиков
Написал уже что-то около трёх тысяч строк кода на #rust, довольно бодренько идёт, уже допилил get/put/putMany методы, коммиты в ручных и автоматических коллекциях, осталось завезти хранение reader'ов, курсоры на выборки и разницы, сборку мусора. Курсоры по разницам будут самыми сложными, но думаю ещё за недельку-другую допилю, а там уже можно будет бенчмарков каких-нибудь сообразить и смотреть, так ли страшны эти RwLock'и.
Больше всего напрягает, что если есть кучка типов-обёрток (например, struct GenerationId(& [u8])), которые вводишь чтобы можно было во-первых им методов добавлять, во-вторых чтобы случайно не присвоить одни байты в другие байты (например, CollectionKey в GenerationId), то потом сильно много бойлерплейта приходится им писать.
Например, есть у меня тип RecordKey(& [u8]), который представляет собой ключ который я использую для записей в RocksDB, у него есть конструктор RecordKey::validate(& [u8]) -> Result<RecordKey, Error>, проверяющий, что байты валидные (там хранится три куска с их размерами, нужно проверить, что размеры не больше чем есть байтов и что лишних нет). Есть метод .to_owned() -> OwnedRecordKey, который делает копию этих байтов. Теперь у нас два типа, делающие одно и то же, но один владеет байтами, а другой просто оборачивает ссылку на них, чтобы методы вызывать на этих байтах. Я был бы рад иметь только OwnedRecordKey, но если я откуда-то получил голые байты и мне нужно их только прочитать, то я не смогу использовать методы из OwnedRecordKey без его конструирования, которое потребует копирования.
По-хорошему сделать бы trait IsRecordKey, в котором определю методы (у меня это getCollectionKey(), getGenerationId(), getPhantomId()), а затем реализовать его для OwnedRecordKey и RecordKey. Но это просто тонна дублирующегося кода на ровном месте, который отличается только наличием & в варианте у OwnedRecordKey.
В итоге приходится реализовывать методы только у RecordKey, а когда нужно использовать их от OwnedRecordKey, то делать .as_ref(), получать экземпляр RecordKey и использовать их от него.
Ну и ладно, когда таких типов две штуки и если там действительно логика какая-то есть. Но когда это совсем тупые обёртки (как в изначальном примере с GenerationId), а у тебя есть ещё три таких, надоедает им методы дописывать для кастований туда-сюда в разные их виды (владеющий, ссылочный, доставания байтов из него, взятия байтов для чтения, взятия байтов для записи).
Я чувствую, что нужно разобраться с макросами, чтобы я мог просто в #[derive(...)] своих Trait'ов дописать и оно там шух-шух-шух, нагенерило мне всего. Но как-то сложновато оно пока выглядит, приходится ныть и продожать плакать, колоться, но жрать кактус.
2 минуты
12 декабря 2022