[HN Gopher] A byte string library for Rust
___________________________________________________________________
A byte string library for Rust
Author : ingve
Score : 243 points
Date : 2022-09-08 07:18 UTC (15 hours ago)
(HTM) web link (blog.burntsushi.net)
(TXT) w3m dump (blog.burntsushi.net)
| Xeoncross wrote:
| If you haven't read https://blog.burntsushi.net/transducers/ yet,
| then IDK what you're doing with your life.
| rwmj wrote:
| Please don't design bit/byte string libraries until you
| understand how Erlang handles them, because that language has by
| far the best support.
| https://www.erlang.org/doc/programming_examples/bit_syntax.h...
|
| Here's my OCaml library influenced heavily by Erlang:
| https://bitstring.software/examples/
| bsder wrote:
| This library isn't about bit packing--it's mostly about
| optimizing text and presumably "ripgrep" which the author is
| also the creator of.
|
| However, I do agree that Erlang's Bit Syntax is, by far, the
| best handling I've ever seen for slicing and dicing bits and
| bytes at the very lowest level.
| throwawaymaths wrote:
| Erlang's bit syntax is actually kind of broken:
|
| See if you can guess correctly what this produces:
| <<1:5, 2:4, 0xFFOO:15, "foo":binary>>
| bsder wrote:
| All manner of errors?
|
| You use a hex literal syntax that doesn't exist--16#FF00 is
| Erlang and how on earth did you get "O" instead of "0".
|
| Once I fix the brokenness:
|
| 10> <<1:5, 2:4, 16#FF00:15, "foo">>.
|
| <<9,127,0,102,111,111>>
|
| Looks ... unsurprising? Maybe it would be nice to get a
| truncation warning on that 16#FF00:15, but otherwise ...
| fine?
|
| This looks like an advertisement that Elixir kind of sucks
| and you should use straight Erlang instead?
|
| Note from downthread: this is broken even in Elixir, so I
| really don't know what your point was.
| rkangel wrote:
| The correct answer to this is actually "syntax error"
| because your `0xFFOO:15` has got two letter O's in it and
| anyway 0xFF00 isn't valid erlang (no hex literals).
|
| If you mean this equivalent bit of Elixir, then I got it
| right:
|
| <<1::5, 2::4, 0xFFOO::15, "foo"::binary>>
|
| I think it's all good and sensible, except that
| "0xFF00::15" should raise an error. The bit syntax silently
| masks out some stuff which can hide some errors.
| throwawaymaths wrote:
| Yeah, sorry typing on phone.
|
| Ok. Maybe I'm just dumb. But I was really surprised that
| the bit order goes from msbit to lsbit (while the byte
| order goes from lsbyte to msbyte). Since the 15 bit
| element crosses over the byte boundary (and overflows it)
| the arrangement -- 00s in byte 1 and 0x80 0x3F in bytes 2
| and 3... is not obvious, to me).
|
| In particular this makes it tricky to reinterpret packed
| structs coming from c, when using NIFs
|
| Specifically, what I would have wanted, was lsb-msb in
| bytes, and an overflow error, or syntax in the descriptor
| modifier that is required if you might overflow.
|
| Or, this would all be solved if we used an RTL layouts
| like the divine one intended.
| rkangel wrote:
| The important thing to remember, it's just a sequence of
| bits (and if that's a multiple of 8 then you can look at
| it as a sequence of bytes instead). Byte boundaries are
| just a way of looking at the result.
|
| You get the bits in the order you ask for in the
| expression, and then it encodes each valuee as you ask.
| Note that the default encoding is big endian, so the
| value 0xFF00 comes out as the bit sequence
| 1111111100000000 wherever it is.
|
| Now converting from a C-struct you absolutely do have to
| think about byte order, but erlang has you there too.
| Let's say you've got this: #pragma
| pack(1) struct { uint16_t a;
| uint8_t b; uint8_t c; uint32_t d;
| };
|
| Then all you do is: <<a::16-native, b::8,
| c::8, d::32-native>> = my_block_of_data
|
| And then all of your values (a, b, c, d) will be correct.
|
| As I said above, erlang defaults to encoding/decoding
| each value as big-endian (e.g. <<0xFF00::16>> is
| equivalent to <<0xFF00::16-big>>. This is the default
| because big endian is used for the vast majority of comms
| protocols (in that context it's also called 'network byte
| order'). When interpreting values in memory though it can
| be either, depending on your processor (although mostly
| -little these days). Using -native as yoru endianness
| means "use big or little as appropriate for my
| processor". It's also a good signal that you're
| interpreting something from memory (as supposed to a
| protocol).
| burntsushi wrote:
| Can you say what is specifically wrong with bstr (while tying
| it to real world use cases) instead of trying to tell me what I
| do or don't understand?
| zozbot234 wrote:
| Much of it has seemingly no reason for being specialized to
| u8, especially the needle/haystack search example that takes
| up much of the blogpost. Even the "replacing invalid UTF-8
| with the generic replacement character" part could simply be
| factored out as an iterator adapter on u8's.
| gliptic wrote:
| It's specialized to &[u8] in order to supply optimized
| implementations.
| burntsushi wrote:
| I think that would be an interesting API design to explore,
| absolutely. I think you'll have a lot of issues making it
| fast though. There is a fair bit of SIMD going on under the
| hoods in both the substring routines and the UTF-8
| validation routines, for example. Building APIs based
| around iterator adapters that munch one byte at a time are
| difficult to square with SIMD optimizations that want to
| operate on a whole bunch of bytes at a time.
|
| Consider, for example, how you might use a routine like
| memchr[1] if all of your public APIs are generic iterator
| adapters.
|
| And then once you get into things like regex engines,
| modifying _them_ to work on Iterator <Item=u8> is a highly
| non-trivial affair. It is of course possible to write _a_
| regex engine that works on such things, but it 's going to
| be limited in performance or capabilities. The way to make
| regexes and streaming work together is probably something
| more like Iterator<Item=&[u8]> (which is perhaps roughly
| analogous to what Hyperscan does). You really want blocks
| of bytes, not one-byte-at-a-time.
|
| [1]: https://github.com/BurntSushi/memchr/blob/8037d11b4357
| b0f07b...
| gpm wrote:
| UTF-8 by definition is a sequence of u8's, what would you
| like it to be generic over, and how would that help
| anyone!?
| brobinson wrote:
| I think the author of ripgrep knows a thing or two about
| processing bits and bytes.
| CodesInChaos wrote:
| Your links seems to use _string_ as a synonym of _sequence_.
| The linked crate is about strings which represent text, and
| many of them assume that the encoding is a superset of ASCII,
| and some ever assume it 's potentially invalid UTF-8.
|
| So I don't see how your links are relevant here.
| rwmj wrote:
| It deals with both bits and byte strings, and as it's
| implemented as a set of compile-time macros there's no
| overhead as long as the compiler can easily see that the
| string is byte-aligned.
| speed_spread wrote:
| It feels like you didn't read the linked article and are
| only using the title to plug your lib. Without discussing
| the relative merits of your work, _you_ might have to learn
| a thing or two about self-promotion opportunities. Step 1:
| "understand what people are talking about before
| participating". Amazingly, this actually applies to all
| conversations.
| lifthrasiir wrote:
| You have solved a different problem. The OP benchmarks grep
| and wc as motivating examples; how does your library (and
| the Erlang design in general) help in such cases?
| Dr_Emann wrote:
| Honestly feels like a very, very different use case from
| utf8-ish strings, at a quick read?
| chungy wrote:
| One thing I noticed in the middle, when concatenating Rust files
| for a demonstration:
|
| > Note also that the files are sorted before concatenating, so
| that the result is guaranteed to be deterministic.
|
| No locale was defined and the example sort command used cannot be
| considered deterministic. The results could vary wildly on
| different systems just through the locale alone!
|
| Two solutions: define the locale ("LC_ALL=C" before the command
| should be sufficient), or use the -V flag on sort.
| burntsushi wrote:
| Ooo, nice catch! Fixed:
| https://github.com/BurntSushi/blog/commit/a1b0e40cbfd293310b...
| chungy wrote:
| Awesome :)
| Fiahil wrote:
| > Should byte strings be added to std?
|
| > Some folks have expressed a desire for bstr or something like
| it to be put into the standard library. I'm not sure how I feel
| about wholesale adopting bstr as it is. bstr is somewhat
| opinionated in that it provides several Unicode operations (like
| grapheme, word and sentence segmentation), for example, that std
| has deliberately chosen to leave to the crate ecosystem.
|
| Yes, ok, but could we -at least- have the same Debug impl bstr
| has ? I'd love to be able to print "human-readable" Vec<u8> :')
| burntsushi wrote:
| That's what the very next paragraph addresses haha.
|
| So the Debug impl for Vec<u8> is just the Debug impl for
| Vec<T>. Doing otherwise means specializing for Vec<u8>, and
| it's not totally clear to me that it makes sense to do that.
| Doing it effectively requires assuming that a Vec<u8>
| everywhere is UTF-8 or close to it.
|
| I do mention that we could add a '[u8]::debug_utf8()' method
| that returns a type with a nice Debug impl for byte strings.
| Kind of like how we have 'Path::display()', but for the Display
| impl. But that is kind of annoying in a way that doesn't really
| apply to Display impls. It's very common to derive(Debug), and
| if the debug impl is only accessible via a method, then
| derive(Debug) doesn't work. So then you have to write your
| Debug impl by hand, which is... annoying.
|
| Anyway, point is, it's just not totally straight-forward to
| bring bstr into std.
|
| As I said in the blog, I think the highest value thing that
| could be brought into std is substring search that works on
| &[u8].
| zozbot234 wrote:
| > It's very common to derive(Debug), and if the debug impl is
| only accessible via a method, then derive(Debug) doesn't
| work.
|
| The right way of doing this is to define custom attributes as
| part of derive(Debug) and derive(Display); the derive
| mechanism can already do this. There's no need for a wrapper
| type to be used.
| burntsushi wrote:
| Yes, it may very well be the case that this is the answer.
| But that feature is not stable today. It would be great to
| re-evaluate once that's available.
| fanf2 wrote:
| I am curious how bstr relates to OsString. Is the difference
| that OsString can be WTF16 on Windows?
| burntsushi wrote:
| OsStr uses WTF-8 on Windows, and just represents the raw
| underlying bytes on Unix.
|
| Byte strings can be WTF-8. They can be anything. The
| problem is that there is no real way to (easily) get the
| underlying WTF-8 bytes of an OsStr on Windows. So there's
| no free conversion to and from byte strings.
|
| I wrote more about this in the bstr docs (and don't miss
| the link to os_str_bytes):
| https://docs.rs/bstr/latest/bstr/#file-paths-and-os-strings
|
| I'd be happy to answer more questions if you have them. :-)
| https://github.com/BurntSushi/bstr/discussions
| dhosek wrote:
| I've toyed with seeing about adding a feature to finl_unicode
| to extend or replace the bstr implementations of
| segmentation, etc. but I don't need it so I probably won't.
| You're welcome to steal my code though. (And hi from reddit-
| land!)
| vlmutolo wrote:
| I've been using this library in production to handle doing
| operations on domain names and it's been incredible. It's one of
| those things that's so easy to use it almost starts to seem
| simple. Like _of course_ we need a library that looks just like
| this. It 's obvious in hindsight, which speaks to great design.
|
| It's especially helpful that the library doesn't require you to
| opt into its own dedicated types, and instead defines extension
| methods on existing types.
|
| Thanks, Andrew!
| burntsushi wrote:
| > It's especially helpful that the library doesn't require you
| to opt into its own dedicated types, and instead defines
| extension methods on existing types.
|
| Fun fact: bstr 0.1 went the route of defining its own dedicated
| types! See: https://docs.rs/bstr/0.1.4/bstr/
|
| But it did indeed quickly prove to be pretty annoying. Because
| you still really want to use &[u8] in places because it's so
| ubiquitous. But to get access to the byte string methods, you
| had to explicitly convert it to another type.
|
| The reason why I went that route initially was so you'd always
| get the good Debug impl. But it ended up not being worth it
| sadly. This issue discusses it a bit more:
| https://github.com/BurntSushi/bstr/issues/5
| epilys wrote:
| This should be in the standard library, but maybe I'm biased.
| In implementing ascii/utf8 plain text protocols like
| IMAP/SMTP just like the grep/ripgrep example in the article,
| I've had to limit myself to u8 slices just because the
| occasional byte might make a grapheme invalid.
| burntsushi wrote:
| Yeah people say this enough that I added a section about it
| to the blog: https://blog.burntsushi.net/bstr/#should-byte-
| strings-be-add...
| epilys wrote:
| The needle/haystack thing is the crucial part as you say
| in the blog. Since grapheme, word separation and sentence
| segmentation rely on rules that are updated on each
| unicode version it indeed would be out of place in the
| standard library. Ideally I'd want them (libicu) on the
| system level, e.g. standardised in POSIX in libc so that
| language developers shouldn't need to worry about them.
| gwbas1c wrote:
| I've always wanted something similar in C#. By convention, byte
| arrays are used for handling arbitrary blobs; but they are
| mutable and don't have the same kind of support that strings
| have. C# strings are immutable and have lots of supporting
| methods.
| rednab wrote:
| These days C# has Span<byte> 1) and ReadOnlySpan<byte> 2) which
| has a whole bunch of string-like methods, but the version of C#
| it requires might be newer than you're happy with.
|
| 1) https://docs.microsoft.com/en-us/dotnet/api/system.span-1
|
| 2) https://docs.microsoft.com/en-
| us/dotnet/api/system.readonlys...
| gwbas1c wrote:
| > but the version of C# it requires might be newer than
| you're happy with
|
| Oh, that's a solvable problem. Thanks!
| jjice wrote:
| Burntsushi is a serious power contributor to the Rust ecosystem.
| Obviously ripgrep and the regex crate are top tier. Big thank you
| from someone who uses your work regularly :)
|
| Also really cool to see more and more rust crates releasing their
| 1.0 versions. I feel like one of the big jumps for Rust (for me
| at least) will be when critical non-stdlib libraries are all 1.0
| and there's less "which one do I choose". I understand
| competition is good in situations (more so opinionated
| frameworks) but I do love that I don't think about what regex
| library to choose since there's one obvious winner with tons of
| community support and resources.
| m12k wrote:
| > I understand competition is good in situations
|
| But also, consolidation at a given layer of an ecosystem allows
| that layer to be treated as a foundation so the next layer on
| top of it can be where the competition happens instead
| bowsamic wrote:
| I don't think always that's a good thing. Every ecosystem
| I've seen that happen in has just bred an army of lazy
| developers who rely on libraries for basically everything.
| xxpor wrote:
| That's not being lazy, it's being sane. Nothing's worse
| than screwing up something basic that should have been
| handled by a library. Leftpad might be on the too many
| libraries end, but that's an extreme example.
| bowsamic wrote:
| I don't agree with the assertion that programmers should
| defer programming to others whenever possible
| vladvasiliu wrote:
| I don't read it as "whenever possible", but rather "for
| non-trivial problems that have already been solved".
| bowsamic wrote:
| To me there is not much difference between that and
| "whenever possible"
| xxpor wrote:
| As a programmer, your value prop/job/business isn't
| delivering code. It's solving business problems. If a
| library lets you do that faster, then it's a good idea.
| Flexing your ability to code has no place in the real
| world.
| bluesnowmonkey wrote:
| Everyone's job in a business is solving business
| problems. Programmers do that mainly by programming.
| Otherwise we wouldn't call them programmers.
| bowsamic wrote:
| Exactly. To me it just seems like a profoundly bad idea
| to become overly reliant on the code of others. Then your
| capability to solve business problems will certainly
| decrease.
| julienfr112 wrote:
| What would be the ratio between the the line (or
| instructions ?) you write yourself and the one you rely
| on (OS, environment, compiler, firmware ...) ? one in a
| million ?
| rcxdude wrote:
| I'm curious what environment you code on where you are
| not extremely reliant on the code of others. you may not
| use many libraries but you are equally dependent on the
| standard library, compiler, and OS you are running on.
| frio wrote:
| Introducing a towering pile of dependencies is
| _introducing_ a business problem; there is a cost of
| ownership to a dependency tree that only grows as it
| grows.
|
| Grabbing a library from somewhere and saying "problem
| solved, onto the next one" isn't a sustainable
| development practice; there has to be some assessment of
| "is this library popular/the maintainer trustworthy/what
| risk do we carry if it gets abandoned/will someone pick
| it up/_does it solve a big enough problem to warrant the
| effort_" that goes with every choice to pick one.
| Further, every single 3rd party dependency carries
| security risks, and every time you add one, you make it
| more likely one of them will get compromised.
|
| I used to be a "just grab the libraries and move on" guy,
| but we're currently working on getting $currentEmployer
| off some old major versions of React, CRA and Spring Boot
| because a previous developer was of the same mindset and
| half the stuff he grabbed has died and isn't forwards
| compatible. It's not a fun process, and many problems the
| libraries solve could've been solved in-house for less
| total effort.
| bowsamic wrote:
| Are you saying that there is no value in honing your
| skills as a programmer?
| orf wrote:
| No. He's saying that while another developer gets stuck
| in the weeds implementing their own byte-string library,
| he'll be past that and shipping the feature that needs a
| byte-string implementation to the customer or end user.
|
| It's the same reason you're writing this using someone
| else's web browser, on someone else's kernel, on someone
| else's hardware.
|
| And it's not because you're a bad/lazy programmer or
| because there's no value in understanding how all of that
| works.
| bowsamic wrote:
| I don't (and won't ever) get it, sorry
| orf wrote:
| You do fully, 100% get it though.
|
| Because you utilise the labour of others every day with
| the knowledge that doing so allows you to achieve what
| you need to achieve, rather than spending all your time
| growing and harvesting corn or something.
| bobbyskelton41 wrote:
| It's basic economics: gains from trade. It's more
| expensive to be entirely self-reliant.
| ZephyrBlu wrote:
| You write your own OS, web browser, etc?
| zaphar wrote:
| Where on earth does he say that? There is no shortage of
| development in any given project. Writing my own http
| client/server, json parser, html parser, networking IO
| library, and a whole host of other stuff doesn't help me
| ship faster. I may experiment with implementations of
| these things on my own to learn more about them but:
|
| 1. Doing my own implementation of any of those things is
| a large amount of effort that isn't directly relevant to
| my needs in any given job.
|
| 2. My first attempts are going to be buggy and incorrect
| providing a source of bugs in my system that I didn't
| need. It would be irresponsible to use them in a work
| product.
|
| 3. I don't learn substantially more about software
| development doing these. I may learn more about http, or
| json parsing but I'm doing so at the expense of learning
| more about my business domain. There is some minimum
| amount I need to know about these things to do my job.
| The rest is unnecessary until I run into a situation
| requiring me to dig deeper. To borrow a Software
| Architecure truism? YAGNI, You ain't gonna need it.
|
| It is a fact that I am deliberately limiting myself if I
| force myself to understand every layer of technology I
| need to leverage in order to do my job rather than
| specializing. I will always have to delegate some of that
| to someone else who has the time to go deep enough to
| provide a robust solution for me. I will also always have
| a responsibility to go deep on some of those things when
| it is relevant to my work.
| rcxdude wrote:
| People who use a lot of libraries still seem to spend
| most of their time programming. I'm not sure why using
| libraries means less practice programming.
| lesuorac wrote:
| The moral of story of leftpad should not have been people
| use too many dependencies.
|
| It should have been don't arbitrarily grab code from the
| web for your production apps. If you had any form of
| caching where a validated library (i.e. leftpad) would be
| used for your builds instead of just reaching out
| everytime then your system wouldn't break. Nor would a
| random cryptominer get into your app.
|
| --
|
| Libraries should be a good thing in that it's definitely
| easier to review a line of code for a bug than write that
| same line bug-free. Of course, people (companies) rarely
| review the libraries they use (sometimes they
| physically/legally can't) so there are some outs.
| dhosek wrote:
| I've always been a bit puzzled by the reluctance to release 1.0
| I can understand if you're flailing around about what the API
| should be or if you don't think your code actually _works_ ,
| but otherwise, why not start at 1.0? The first public release
| of finl_unicode was 1.0 (there ended up being 1.0.1 and 1.0.2
| to fix some issues with docs.rs requirements that could not be
| anticipated), but the API was predetermined and I have good
| tests so I know my code is accurate so why not release as 1.0?
| burntsushi wrote:
| OK, so unfortunately, this issue gets really tangled. I could
| give you a short answer, but that will invite a question. And
| then my answer to that question is likely to invite another.
| I've had this conversation many times and it always goes the
| same way. So I will try to anticipate those questions, but...
| it's subtle.
|
| > I've always been a bit puzzled
|
| I'll respond with my reasons, but I want to emphasize that I
| am be _descriptive_ , not _prescriptive_.
|
| The main reason why I don't just start with 1.0 out of the
| gate is because I generally want 1.0 to indicate some level
| of maturity and stability. That is, once I publish 1.0,
| ideally, I won't publish a 2.0. Or if I do, that timeline
| will be measured in years. It takes a while to get that kind
| of confidence with a library's API. If I had started with
| bstr 1.0, then this blog post would be talking about bstr
| 3.0. Not 1.0. Empirically, bstr 1.0 would not have been the
| commitment to stability that I want 1.0 to mean.
|
| So, first question at this point is usually: well why not
| just increase x in x.0.0 as needed? It's okay to have 1.0 and
| 2.0 and 3.0. We have semver after all!
|
| What I say to that is, yes, absolutely, you can do that. But
| it's absolutely a preference with respect to how often you
| want to release breaking change releases. My preference is to
| do it very rarely. Or as rarely as I can manage. The main
| practical reason for it is that breaking change releases
| create churn, and they lead to transition periods where, in
| the best of cases, compilation times take a hit.
|
| For example, if I released regex 2.0, no code would break. At
| some point, people would start migrating to it. And for some
| period of time, it's likely that many projects would be
| building both regex 1.0 and regex 2.0 in their dependency
| trees. regex is not exactly lightweight, and so people are
| going to hunt down these issues in their trees and get
| everyone to migrate to regex 2.0. It's work. It's tedious.
| It's annoying. If I start putting out new breaking change
| releases of the regex crate frequently, then I'm going to
| annoy people in a way that is proportional to the frequency
| of releases. By committing to a policy that 1.0 means "I'm
| unlikely to publish a breaking change release for at least a
| few years," then that 1.0 is going to be a signal to folks
| that they are signing up for a dependency that is probably
| not going to cause them churn.
|
| It's also especially important for bstr, because folks want
| to use it as a public dependency. So if I'm releasing semver
| incompatible releases frequently, then that's going to cause
| a lot of painful churn for users of bstr. It no longer just
| becomes a matter of compilation times. But you'll need to get
| your entire dependency tree migrated over, or else you risk
| things not working if multiple crates try to interoperate via
| bstr's API.
|
| I suppose the next question at this point is, "but it's just
| a version number, why attach special significance to it that
| isn't in semver?" semver is useful for communicating breaking
| changes. And I think it's also useful to use the version
| number to communicate stability as well. But to be totally
| clear here: I am (EDIT) NOT trying to be an advocate here.
| I'm not saying this is what you or what everyone should do.
| There are trade offs here. I tend to build library crates
| that others build on, so my bias is to move slowly. But if I
| built crates (and I do) that are closer to the application
| (or even an application itself), then I'm generally much
| happier to just push out breaking change releases at a higher
| frequency.
|
| I think the last question is, "but anything goes in 0.x.y, so
| says semver, so now people never know if they're getting a
| breaking release or not." Indeed, that is what semver says,
| and if that were how Cargo implemented semver, I'd probably
| start with 1.0 releases. (Or at the very least, publish a 1.0
| release much much sooner.) But Cargo does not implement
| semver that way. With Cargo, 0.x.y is semver incompatible
| with 0.(x+1).z. That is, incrementing the leftmost non-zero
| digit in a version creates a new semver incompatible release
| from Cargo's perspective. So I get all the benefits of semver
| when I use 0.x.y, without needing to publish 1.0.0. The main
| downside is that the 'minor' and 'patch' components of the
| version number get collapsed into one number. But I can live
| with that until I publish 1.0.
| kibwen wrote:
| _> It 's also especially important for bstr, because folks
| want to use it as a public dependency._
|
| Worth highlighting this part. If a crate exposes types that
| are likely to be exposed from the public APIs of _other_
| crates, then that changes the calculus of how disruptive a
| breaking change will be.
| pizza234 wrote:
| Following semantic versioning, libraries are essentially
| allowed to change very liberally on 0.x, so it makes sense to
| reach 1.0 only once the crate/API is stable.
| burntsushi wrote:
| Just to be super clear, while that is true of semver, Cargo
| implements something a little different. Namely, Cargo
| treats _any_ difference in the leftmost non-zero digit of a
| version number as semver incompatible. So if you have 'foo
| = "0.1.2"' and then 'foo' 0.2.0 is published, Cargo will
| not automatically upgrade you when you run 'cargo update'.
| You'll have to explicitly opt into the new 0.2.0 version
| because it's treated as a potentially breaking release.
|
| In effect, this lets you get the benefits of semver
| (communication of breaking changes) without publishing 1.0.
| Thus, there is less pressure in the Rust crate ecosystem to
| publish 1.0.
| loudmax wrote:
| I interpret a major version number release as a commitment
| that the API won't make breaking changes. So releasing a 1.0
| version of a library is kind of like promising that you'll
| make some attempt not to drastically alter the behavior. If
| you're doing this as a hobby or side project you might not
| want to make that kind of commitment.
| db48x wrote:
| That is exactly what I need for one of my long-neglected
| projects. Thank you!
| baq wrote:
| as usual a reminder that ripgrep is _the_ grep tool. if you 're
| using vscode's Find in Files, you're using ripgrep.
___________________________________________________________________
(page generated 2022-09-08 23:02 UTC)