I'm assuming it's a master rather than a slave. There are three stacks I use:
1) Simple blocking API, no error or time out handling
2) Event driven FSM, no error or time out handling
3) Event driven FSM, error and time out handling
If you can get away with 1), it saves an awful lot of grief, and for I2C slaves that only need initialisation it makes sense.
For a lot of slaves, if they don't respond in an anticipated manner immediately, then there is often a hardware error anyway. However for things like EEPROMS that typically need a lengthy delay for writing and erasing, it is often necessary to implement an FSM.
Adding in time out and error handling, and clock stretching, multi-master etc can be gilding the lily in a lot of applications, but sometimes it's necessary, at the expense of adding significant complexity.